push
This commit is contained in:
parent
885503a767
commit
18bdb4d4d5
531
App.vue
531
App.vue
@ -1,273 +1,270 @@
|
||||
<script>
|
||||
/**
|
||||
* vuex管理登录状态,具体可以参考官方登录模板示例
|
||||
*/
|
||||
import { mapMutations } from "vuex";
|
||||
import APPUpdate from "@/plugins/APPUpdate";
|
||||
import { getClipboardData } from "@/js_sdk/h5-copy/h5-copy.js";
|
||||
import config from "@/config/config";
|
||||
// 区域code
|
||||
import provinceList from "./json/area_province.js";
|
||||
import cityList from "./json/area_city.js";
|
||||
import districtList from "./json/area_district.js";
|
||||
import storage from "@/utils/storage.js"; //缓存
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
config,
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 监听返回
|
||||
*/
|
||||
onBackPress(e) {
|
||||
if (e.from == "backbutton") {
|
||||
let routes = getCurrentPages();
|
||||
let curRoute = routes[routes.length - 1].options;
|
||||
routes.forEach((item) => {
|
||||
if (
|
||||
item.route == "pages/tabbar/cart/cartList" ||
|
||||
item.route.indexOf("pages/product/goods") != -1
|
||||
) {
|
||||
uni.redirectTo({
|
||||
url: item.route,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (curRoute.addId) {
|
||||
uni.reLaunch({
|
||||
url: "/pages/tabbar/cart/cartList",
|
||||
});
|
||||
} else {
|
||||
uni.navigateBack();
|
||||
}
|
||||
return true; //阻止默认返回行为
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["login"]),
|
||||
},
|
||||
onLaunch: function () {
|
||||
// #ifdef APP-PLUS
|
||||
this.checkArguments(); // 检测启动参数
|
||||
APPUpdate();
|
||||
this.hanleTabCenter();
|
||||
// 重点是以下: 一定要监听后台恢复 !一定要
|
||||
plus.globalEvent.addEventListener("newintent", (e) => {
|
||||
this.checkArguments(); // 检测启动参数
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
this.applyUpdateWeChat();
|
||||
// #endif
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// #ifndef H5
|
||||
this.getClipboard();
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
//
|
||||
hanleTabCenter() {
|
||||
// 点击中间的➕
|
||||
uni.onTabBarMidButtonTap(() => {
|
||||
console.log("center");
|
||||
// 未登录不能发布视频
|
||||
let myUserInfo = storage.getVlogUserInfo() || null;
|
||||
if (myUserInfo == null) {
|
||||
uni.navigateTo({
|
||||
// url: "../loginRegist/loginRegist",
|
||||
url: "/pages/passport/login",
|
||||
animationType: "slide-in-bottom",
|
||||
success() {
|
||||
this.loginWords = "请登录";
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.chooseVideo({
|
||||
sourceType: ["album"],
|
||||
compressed: false,
|
||||
success(e) {
|
||||
console.log(JSON.stringify(e));
|
||||
uni.navigateTo({
|
||||
url:
|
||||
"/pages/publish/publish?fileObjectEvent=" + JSON.stringify(e),
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 微信小程序版本提交更新版本 解决缓存问题
|
||||
*/
|
||||
applyUpdateWeChat() {
|
||||
const updateManager = uni.getUpdateManager();
|
||||
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
});
|
||||
|
||||
updateManager.onUpdateReady(function (res) {
|
||||
uni.showModal({
|
||||
title: "更新提示",
|
||||
content: "发现新版本,是否重启应用?",
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate();
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
updateManager.onUpdateFailed(function (res) {
|
||||
// 新的版本下载失败
|
||||
});
|
||||
},
|
||||
|
||||
// TODO 开屏广告 后续优化添加
|
||||
launch() {
|
||||
try {
|
||||
// 获取本地存储中launchFlag标识 开屏广告
|
||||
const value = uni.getStorageSync("launchFlag");
|
||||
if (!value) {
|
||||
// this.$u.route("/pages/index/agreement");
|
||||
} else {
|
||||
//app启动时打开启动广告页
|
||||
var w = plus.webview.open(
|
||||
"/hybrid/html/advertise/advertise.html",
|
||||
"本地地址",
|
||||
{
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
zindex: 999,
|
||||
},
|
||||
"fade-in",
|
||||
500
|
||||
);
|
||||
//设置定时器,4s后关闭启动广告页
|
||||
setTimeout(function () {
|
||||
plus.webview.close(w);
|
||||
APPUpdate();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
// error
|
||||
uni.setStorage({
|
||||
key: "launchFlag",
|
||||
data: true,
|
||||
success: function () {
|
||||
console.log("error时存储launchFlag");
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取粘贴板数据
|
||||
*/
|
||||
async getClipboard() {
|
||||
let res = await getClipboardData();
|
||||
/**
|
||||
* 解析粘贴板数据
|
||||
*/
|
||||
if (res.indexOf(config.shareLink) != -1) {
|
||||
uni.showModal({
|
||||
title: "提示",
|
||||
content: "检测到一个分享链接是否跳转?",
|
||||
confirmText: "跳转",
|
||||
success: function (callback) {
|
||||
if (callback.confirm) {
|
||||
const path = res.split(config.shareLink)[1];
|
||||
if (path.indexOf("tabbar") != -1) {
|
||||
uni.switchTab({
|
||||
url: path,
|
||||
});
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: path,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* h5中打开app获取跳转app的链接并跳转
|
||||
*/
|
||||
checkArguments() {
|
||||
// #ifdef APP-PLUS
|
||||
setTimeout(() => {
|
||||
const args = plus.runtime.arguments;
|
||||
if (args) {
|
||||
const argsStr = decodeURIComponent(args);
|
||||
const path = argsStr.split("//")[1];
|
||||
if (path.indexOf("tabbar") != -1) {
|
||||
uni.switchTab({
|
||||
url: `/${path}`,
|
||||
});
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/${path}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<script>
|
||||
/**
|
||||
* vuex管理登录状态,具体可以参考官方登录模板示例
|
||||
*/
|
||||
import { mapMutations } from 'vuex';
|
||||
import APPUpdate from '@/plugins/APPUpdate';
|
||||
import { getClipboardData } from '@/js_sdk/h5-copy/h5-copy.js';
|
||||
import config from '@/config/config';
|
||||
// 区域code
|
||||
import provinceList from './json/area_province.js';
|
||||
import cityList from './json/area_city.js';
|
||||
import districtList from './json/area_district.js';
|
||||
import storage from '@/utils/storage.js'; //缓存
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
config
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* 监听返回
|
||||
*/
|
||||
onBackPress(e) {
|
||||
if (e.from == 'backbutton') {
|
||||
let routes = getCurrentPages();
|
||||
let curRoute = routes[routes.length - 1].options;
|
||||
routes.forEach((item) => {
|
||||
if (item.route == 'pages/tabbar/cart/cartList' || item.route.indexOf('pages/product/goods') != -1) {
|
||||
uni.redirectTo({
|
||||
url: item.route
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (curRoute.addId) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/tabbar/cart/cartList'
|
||||
});
|
||||
} else {
|
||||
uni.navigateBack();
|
||||
}
|
||||
return true; //阻止默认返回行为
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(['login'])
|
||||
},
|
||||
onLaunch: function () {
|
||||
// #ifdef APP-PLUS
|
||||
this.checkArguments(); // 检测启动参数
|
||||
APPUpdate();
|
||||
this.hanleTabCenter();
|
||||
// 重点是以下: 一定要监听后台恢复 !一定要
|
||||
plus.globalEvent.addEventListener('newintent', (e) => {
|
||||
this.checkArguments(); // 检测启动参数
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
this.applyUpdateWeChat();
|
||||
// #endif
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// #ifndef H5
|
||||
this.getClipboard();
|
||||
// #endif
|
||||
},
|
||||
methods: {
|
||||
//
|
||||
hanleTabCenter() {
|
||||
// 点击中间的➕
|
||||
uni.onTabBarMidButtonTap(() => {
|
||||
console.log('center');
|
||||
// 未登录不能发布视频
|
||||
let myUserInfo = storage.getVlogUserInfo();
|
||||
if (myUserInfo == null) {
|
||||
uni.navigateTo({
|
||||
// url: "../loginRegist/loginRegist",
|
||||
url: '/pages/passport/login',
|
||||
animationType: 'slide-in-bottom',
|
||||
success() {
|
||||
this.loginWords = '请登录';
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.chooseVideo({
|
||||
sourceType: ['album'],
|
||||
compressed: false,
|
||||
success(e) {
|
||||
console.log(JSON.stringify(e));
|
||||
uni.navigateTo({
|
||||
url: '/pages/publish/publish?fileObjectEvent=' + JSON.stringify(e)
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 微信小程序版本提交更新版本 解决缓存问题
|
||||
*/
|
||||
applyUpdateWeChat() {
|
||||
const updateManager = uni.getUpdateManager();
|
||||
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
});
|
||||
|
||||
updateManager.onUpdateReady(function (res) {
|
||||
uni.showModal({
|
||||
title: '更新提示',
|
||||
content: '发现新版本,是否重启应用?',
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
updateManager.onUpdateFailed(function (res) {
|
||||
// 新的版本下载失败
|
||||
});
|
||||
},
|
||||
|
||||
// TODO 开屏广告 后续优化添加
|
||||
launch() {
|
||||
try {
|
||||
// 获取本地存储中launchFlag标识 开屏广告
|
||||
const value = uni.getStorageSync('launchFlag');
|
||||
if (!value) {
|
||||
// this.$u.route("/pages/index/agreement");
|
||||
} else {
|
||||
//app启动时打开启动广告页
|
||||
var w = plus.webview.open(
|
||||
'/hybrid/html/advertise/advertise.html',
|
||||
'本地地址',
|
||||
{
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
zindex: 999
|
||||
},
|
||||
'fade-in',
|
||||
500
|
||||
);
|
||||
//设置定时器,4s后关闭启动广告页
|
||||
setTimeout(function () {
|
||||
plus.webview.close(w);
|
||||
APPUpdate();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
// error
|
||||
uni.setStorage({
|
||||
key: 'launchFlag',
|
||||
data: true,
|
||||
success: function () {
|
||||
console.log('error时存储launchFlag');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取粘贴板数据
|
||||
*/
|
||||
async getClipboard() {
|
||||
let res = await getClipboardData();
|
||||
/**
|
||||
* 解析粘贴板数据
|
||||
*/
|
||||
if (res.indexOf(config.shareLink) != -1) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '检测到一个分享链接是否跳转?',
|
||||
confirmText: '跳转',
|
||||
success: function (callback) {
|
||||
if (callback.confirm) {
|
||||
const path = res.split(config.shareLink)[1];
|
||||
if (path.indexOf('tabbar') != -1) {
|
||||
uni.switchTab({
|
||||
url: path
|
||||
});
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: path
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* h5中打开app获取跳转app的链接并跳转
|
||||
*/
|
||||
checkArguments() {
|
||||
// #ifdef APP-PLUS
|
||||
setTimeout(() => {
|
||||
const args = plus.runtime.arguments;
|
||||
if (args) {
|
||||
const argsStr = decodeURIComponent(args);
|
||||
const path = argsStr.split('//')[1];
|
||||
if (path.indexOf('tabbar') != -1) {
|
||||
uni.switchTab({
|
||||
url: `/${path}`
|
||||
});
|
||||
} else {
|
||||
uni.navigateTo({
|
||||
url: `/${path}`
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
/* #ifndef APP-NVUE */
|
||||
@import "uview-ui/index.scss";
|
||||
/* #endif */
|
||||
|
||||
// -------适配底部安全区 苹果x系列刘海屏
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
.mp-iphonex-bottom {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
box-sizing: content-box;
|
||||
height: auto !important;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
// #endif
|
||||
@import 'uview-ui/index.scss';
|
||||
/* #endif */
|
||||
|
||||
// -------适配底部安全区 苹果x系列刘海屏
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
.mp-iphonex-bottom {
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
box-sizing: content-box;
|
||||
height: auto !important;
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
// #endif
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
body {
|
||||
background-color: $bg-color;
|
||||
}
|
||||
body {
|
||||
background-color: $bg-color;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/************************ */
|
||||
.w200 {
|
||||
width: 200rpx !important;
|
||||
}
|
||||
|
||||
.flex1 {
|
||||
flex: 1; //必须父级设置flex
|
||||
}
|
||||
.activate-line {
|
||||
background-color: #ffffff;
|
||||
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
// uni-page-body,
|
||||
// html,
|
||||
// body,
|
||||
// page {
|
||||
// width: 100% ;
|
||||
// height: 100% ;
|
||||
// overflow: hidden;
|
||||
// }
|
||||
</style>
|
||||
|
||||
/************************ */
|
||||
.w200 {
|
||||
width: 200rpx !important;
|
||||
}
|
||||
|
||||
.flex1 {
|
||||
flex: 1; //必须父级设置flex
|
||||
}
|
||||
.activate-line {
|
||||
background-color: #ffffff;
|
||||
|
||||
transition-duration: 300ms;
|
||||
}
|
||||
// uni-page-body,
|
||||
// html,
|
||||
// body,
|
||||
// page {
|
||||
// width: 100% ;
|
||||
// height: 100% ;
|
||||
// overflow: hidden;
|
||||
// }
|
||||
</style>
|
||||
|
||||
@ -1,60 +1,60 @@
|
||||
body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p {
|
||||
margin:0;
|
||||
padding:0;
|
||||
font-style:normal;
|
||||
|
||||
/* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */
|
||||
}
|
||||
|
||||
ol, ul, li {
|
||||
list-style:none;
|
||||
}
|
||||
|
||||
img {
|
||||
border:0;
|
||||
vertical-align:middle;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
body{
|
||||
height: 100% important;
|
||||
color:#000;
|
||||
background:#FFF;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear:both;
|
||||
height:1px;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
margin-top:-1px;
|
||||
}
|
||||
|
||||
a {
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
user-select: auto;
|
||||
}
|
||||
|
||||
input:focus, input:active, textarea:focus, textarea:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.chat-aside {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
box-sizing: border-box;
|
||||
width: 360px !important;
|
||||
border-radius: 8px 0 0 8px;
|
||||
z-index: 9999;
|
||||
max-height: calc(100% - 50px);
|
||||
}
|
||||
body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p {
|
||||
margin:0;
|
||||
padding:0;
|
||||
font-style:normal;
|
||||
|
||||
/* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */
|
||||
}
|
||||
|
||||
ol, ul, li {
|
||||
list-style:none;
|
||||
}
|
||||
|
||||
img {
|
||||
border:0;
|
||||
vertical-align:middle;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
body{
|
||||
height: 100% important;
|
||||
color:#000;
|
||||
background:#FFF;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear:both;
|
||||
height:1px;
|
||||
width:100%;
|
||||
overflow:hidden;
|
||||
margin-top:-1px;
|
||||
}
|
||||
|
||||
a {
|
||||
color:#000;
|
||||
text-decoration:none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
user-select: auto;
|
||||
}
|
||||
|
||||
input:focus, input:active, textarea:focus, textarea:active {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.chat-aside {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
box-sizing: border-box;
|
||||
width: 360px !important;
|
||||
border-radius: 8px 0 0 8px;
|
||||
z-index: 9999;
|
||||
max-height: calc(100% - 50px);
|
||||
}
|
||||
|
||||
@ -1,324 +1,325 @@
|
||||
<template>
|
||||
<div class="chat" :style="{height:fn+'px'}">
|
||||
<div :style="{height:'100%'}" :class="['tui-chat', !isPC && 'tui-chat-h5']">
|
||||
<div
|
||||
v-if="!currentConversationID"
|
||||
:class="['tui-chat-default', !isPC && 'tui-chat-h5-default']"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
v-if="currentConversationID"
|
||||
:class="['tui-chat', !isPC && 'tui-chat-h5']"
|
||||
>
|
||||
<ChatHeader
|
||||
:class="[
|
||||
'tui-chat-header',
|
||||
!isPC && 'tui-chat-H5-header',
|
||||
isUniFrameWork && 'tui-chat-uniapp-header',
|
||||
]"
|
||||
:isGroup="isGroup"
|
||||
:headerExtensionList="headerExtensionList"
|
||||
@closeChat="closeChat"
|
||||
@openGroupManagement="handleGroup"
|
||||
/>
|
||||
<Forward @toggleMultipleSelectMode="toggleMultipleSelectMode" />
|
||||
<MessageList
|
||||
ref="messageListRef"
|
||||
:class="['tui-chat-message-list', !isPC && 'tui-chat-h5-message-list']"
|
||||
:isGroup="isGroup"
|
||||
:groupID="groupID"
|
||||
:isNotInGroup="isNotInGroup"
|
||||
:isMultipleSelectMode="isMultipleSelectMode"
|
||||
@handleEditor="handleEditor"
|
||||
@closeInputToolBar="() => changeToolbarDisplayType('none')"
|
||||
@toggleMultipleSelectMode="toggleMultipleSelectMode"
|
||||
/>
|
||||
<div
|
||||
v-if="isNotInGroup"
|
||||
:class="{
|
||||
'tui-chat-leave-group': true,
|
||||
'tui-chat-leave-group-mobile': isMobile,
|
||||
}"
|
||||
>
|
||||
{{ leaveGroupReasonText }}
|
||||
</div>
|
||||
<MultipleSelectPanel
|
||||
v-else-if="isMultipleSelectMode"
|
||||
@oneByOneForwardMessage="oneByOneForwardMessage"
|
||||
@mergeForwardMessage="mergeForwardMessage"
|
||||
@toggleMultipleSelectMode="toggleMultipleSelectMode"
|
||||
/>
|
||||
<template v-else>
|
||||
<MessageInputToolbar
|
||||
v-if="isInputToolbarShow"
|
||||
:class="[
|
||||
'tui-chat-message-input-toolbar',
|
||||
!isPC && 'tui-chat-h5-message-input-toolbar',
|
||||
isUniFrameWork && 'tui-chat-uni-message-input-toolbar'
|
||||
]"
|
||||
:displayType="inputToolbarDisplayType"
|
||||
@insertEmoji="insertEmoji"
|
||||
@changeToolbarDisplayType="changeToolbarDisplayType"
|
||||
@scrollToLatestMessage="scrollToLatestMessage"
|
||||
/>
|
||||
<MessageInput
|
||||
ref="messageInputRef"
|
||||
:class="[
|
||||
'tui-chat-message-input',
|
||||
!isPC && 'tui-chat-h5-message-input',
|
||||
isUniFrameWork && 'tui-chat-uni-message-input',
|
||||
isWeChat && 'tui-chat-wx-message-input',
|
||||
]"
|
||||
:enableAt="featureConfig.InputMention"
|
||||
:isMuted="false"
|
||||
:muteText="TUITranslateService.t('TUIChat.您已被管理员禁言')"
|
||||
:placeholder="TUITranslateService.t('TUIChat.请输入消息')"
|
||||
:inputToolbarDisplayType="inputToolbarDisplayType"
|
||||
@changeToolbarDisplayType="changeToolbarDisplayType"
|
||||
|
||||
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<!-- Group Management -->
|
||||
<div
|
||||
v-if="!isNotInGroup && !isApp && isUniFrameWork && isGroup && headerExtensionList.length > 0"
|
||||
class="group-profile"
|
||||
@click="handleGroup"
|
||||
>
|
||||
{{ headerExtensionList[0].text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, computed } from '../../adapter-vue';
|
||||
import TUIChatEngine, {
|
||||
TUITranslateService,
|
||||
TUIConversationService,
|
||||
TUIStore,
|
||||
StoreName,
|
||||
IMessageModel,
|
||||
IConversationModel,
|
||||
} from '@tencentcloud/chat-uikit-engine';
|
||||
import TUICore, { TUIConstants, ExtensionInfo } from '@tencentcloud/tui-core';
|
||||
import ChatHeader from './chat-header/index.vue';
|
||||
import MessageList from './message-list/index.vue';
|
||||
import MessageInput from './message-input/index.vue';
|
||||
import MultipleSelectPanel from './mulitple-select-panel/index.vue';
|
||||
import Forward from './forward/index.vue';
|
||||
import MessageInputToolbar from './message-input-toolbar/index.vue';
|
||||
import { isPC, isWeChat, isUniFrameWork, isMobile, isApp } from '../../utils/env';
|
||||
import { ToolbarDisplayType } from '../../interface';
|
||||
import TUIChatConfig from './config';
|
||||
// @Start uniapp use Chat only
|
||||
import { onLoad, onUnload,onNavigationBarButtonTap } from '@dcloudio/uni-app';
|
||||
import { initChat, logout } from './entry-chat-only.ts';
|
||||
|
||||
onLoad((options) => {
|
||||
initChat(options);
|
||||
});
|
||||
|
||||
onUnload(() => {
|
||||
// Whether logout is decided by yourself when the page is unloaded. The default is false.
|
||||
logout(false).then(() => {
|
||||
// Handle success result from promise.then when you set true.
|
||||
}).catch(() => {
|
||||
// handle error
|
||||
});
|
||||
});
|
||||
// @End uniapp use Chat only
|
||||
|
||||
const emits = defineEmits(['closeChat']);
|
||||
const fn = uni.getSystemInfoSync().windowHeight
|
||||
const groupID = ref(undefined);
|
||||
const isGroup = ref(false);
|
||||
const isNotInGroup = ref(false);
|
||||
const notInGroupReason = ref<number>();
|
||||
const currentConversationID = ref();
|
||||
const isMultipleSelectMode = ref(false);
|
||||
const inputToolbarDisplayType = ref<ToolbarDisplayType>('none');
|
||||
const messageInputRef = ref();
|
||||
const messageListRef = ref<InstanceType<typeof MessageList>>();
|
||||
const headerExtensionList = ref<ExtensionInfo[]>([]);
|
||||
const featureConfig = TUIChatConfig.getFeatureConfig();
|
||||
|
||||
onNavigationBarButtonTap((e) => {
|
||||
if (isGroup.value) {
|
||||
handleGroup();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdate,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdate,
|
||||
});
|
||||
reset();
|
||||
});
|
||||
|
||||
const isInputToolbarShow = computed<boolean>(() => {
|
||||
return isUniFrameWork ? inputToolbarDisplayType.value !== 'none' : true;
|
||||
});
|
||||
|
||||
const leaveGroupReasonText = computed<string>(() => {
|
||||
let text = '';
|
||||
switch (notInGroupReason.value) {
|
||||
case 4:
|
||||
text = TUITranslateService.t('TUIChat.您已被管理员移出群聊');
|
||||
break;
|
||||
case 5:
|
||||
text = TUITranslateService.t('TUIChat.该群聊已被解散');
|
||||
break;
|
||||
case 8:
|
||||
text = TUITranslateService.t('TUIChat.您已退出该群聊');
|
||||
break;
|
||||
default:
|
||||
text = TUITranslateService.t('TUIChat.您已退出该群聊');
|
||||
break;
|
||||
}
|
||||
return text;
|
||||
});
|
||||
|
||||
const reset = () => {
|
||||
TUIConversationService.switchConversation('');
|
||||
};
|
||||
|
||||
const closeChat = (conversationID: string) => {
|
||||
emits('closeChat', conversationID);
|
||||
reset();
|
||||
};
|
||||
|
||||
const insertEmoji = (emojiObj: object) => {
|
||||
messageInputRef.value?.insertEmoji(emojiObj);
|
||||
};
|
||||
|
||||
const handleEditor = (message: IMessageModel, type: string) => {
|
||||
if (!message || !type) return;
|
||||
switch (type) {
|
||||
case 'reference':
|
||||
// todo
|
||||
break;
|
||||
case 'reply':
|
||||
// todo
|
||||
break;
|
||||
case 'reedit':
|
||||
if (message?.payload?.text) {
|
||||
messageInputRef?.value?.reEdit(message?.payload?.text);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const handleGroup = () => {
|
||||
headerExtensionList.value[0].listener.onClicked({ groupID: groupID.value });
|
||||
uni.navigateTo({
|
||||
url: `/TUIKit/components/TUIGroup/index`
|
||||
});
|
||||
};
|
||||
|
||||
function changeToolbarDisplayType(type: ToolbarDisplayType) {
|
||||
inputToolbarDisplayType.value = inputToolbarDisplayType.value === type ? 'none' : type;
|
||||
if (inputToolbarDisplayType.value !== 'none' && isUniFrameWork) {
|
||||
uni.$emit('scroll-to-bottom');
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToLatestMessage() {
|
||||
messageListRef.value?.scrollToLatestMessage();
|
||||
}
|
||||
|
||||
function toggleMultipleSelectMode(visible?: boolean) {
|
||||
isMultipleSelectMode.value = visible === undefined ? !isMultipleSelectMode.value : visible;
|
||||
}
|
||||
|
||||
function mergeForwardMessage() {
|
||||
messageListRef.value?.mergeForwardMessage();
|
||||
}
|
||||
|
||||
function oneByOneForwardMessage() {
|
||||
messageListRef.value?.oneByOneForwardMessage();
|
||||
}
|
||||
|
||||
function updateUIUserNotInGroup(conversation: IConversationModel) {
|
||||
if (conversation?.operationType > 0) {
|
||||
headerExtensionList.value = [];
|
||||
isNotInGroup.value = true;
|
||||
/**
|
||||
* 4 - be removed from the group
|
||||
* 5 - group is dismissed
|
||||
* 8 - quit group
|
||||
*/
|
||||
notInGroupReason.value = conversation?.operationType;
|
||||
} else {
|
||||
isNotInGroup.value = false;
|
||||
notInGroupReason.value = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onCurrentConversationUpdate(conversation: IConversationModel) {
|
||||
updateUIUserNotInGroup(conversation);
|
||||
// return when currentConversation is null
|
||||
if (!conversation) {
|
||||
return;
|
||||
}
|
||||
// return when currentConversationID.value is the same as conversation.conversationID.
|
||||
if (currentConversationID.value === conversation?.conversationID) {
|
||||
return;
|
||||
}
|
||||
|
||||
isGroup.value = false;
|
||||
let conversationType = TUIChatEngine.TYPES.CONV_C2C;
|
||||
const conversationID = conversation.conversationID;
|
||||
if (conversationID.startsWith(TUIChatEngine.TYPES.CONV_GROUP)) {
|
||||
conversationType = TUIChatEngine.TYPES.CONV_GROUP;
|
||||
isGroup.value = true;
|
||||
groupID.value = conversationID.replace(TUIChatEngine.TYPES.CONV_GROUP, '');
|
||||
}
|
||||
|
||||
headerExtensionList.value = [];
|
||||
isMultipleSelectMode.value = false;
|
||||
// Initialize chatType
|
||||
TUIChatConfig.setChatType(conversationType);
|
||||
// While converstaion change success, notify callkit and roomkit、or other components.
|
||||
TUICore.notifyEvent(TUIConstants.TUIChat.EVENT.CHAT_STATE_CHANGED, TUIConstants.TUIChat.EVENT_SUB_KEY.CHAT_OPENED, { groupID: groupID.value });
|
||||
// The TUICustomerServicePlugin plugin determines if the current conversation is a customer service conversation, then sets chatType and activates the conversation.
|
||||
TUICore.callService({
|
||||
serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
|
||||
method: TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
|
||||
params: { conversationID: conversationID },
|
||||
});
|
||||
// When open chat in room, close main chat ui and reset theme.
|
||||
if (TUIChatConfig.getChatType() === TUIConstants.TUIChat.TYPE.ROOM) {
|
||||
if (TUIChatConfig.getFeatureConfig(TUIConstants.TUIChat.FEATURE.InputVoice) === true) {
|
||||
TUIChatConfig.setTheme('light');
|
||||
currentConversationID.value = '';
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Get chat header extensions
|
||||
if (TUIChatConfig.getChatType() === TUIConstants.TUIChat.TYPE.GROUP) {
|
||||
headerExtensionList.value = TUICore.getExtensionList(TUIConstants.TUIChat.EXTENSION.CHAT_HEADER.EXT_ID);
|
||||
}
|
||||
TUIStore.update(StoreName.CUSTOM, 'activeConversation', conversationID);
|
||||
currentConversationID.value = conversationID;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss" src="./style/index.scss">
|
||||
.chat{
|
||||
width: 100% !important;
|
||||
height: 100vh !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
</style>
|
||||
<template>
|
||||
<div class="chat" :style="{height:fn+'px'}">
|
||||
<div :style="{height:'100%'}" :class="['tui-chat', !isPC && 'tui-chat-h5']">
|
||||
<div
|
||||
v-if="!currentConversationID"
|
||||
:class="['tui-chat-default', !isPC && 'tui-chat-h5-default']"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
v-if="currentConversationID"
|
||||
:class="['tui-chat', !isPC && 'tui-chat-h5']"
|
||||
>
|
||||
<ChatHeader
|
||||
:class="[
|
||||
'tui-chat-header',
|
||||
!isPC && 'tui-chat-H5-header',
|
||||
isUniFrameWork && 'tui-chat-uniapp-header',
|
||||
]"
|
||||
:isGroup="isGroup"
|
||||
:headerExtensionList="headerExtensionList"
|
||||
@closeChat="closeChat"
|
||||
@openGroupManagement="handleGroup"
|
||||
/>
|
||||
<Forward @toggleMultipleSelectMode="toggleMultipleSelectMode" />
|
||||
<MessageList
|
||||
ref="messageListRef"
|
||||
:class="['tui-chat-message-list', !isPC && 'tui-chat-h5-message-list']"
|
||||
:isGroup="isGroup"
|
||||
:groupID="groupID"
|
||||
:isNotInGroup="isNotInGroup"
|
||||
:isMultipleSelectMode="isMultipleSelectMode"
|
||||
@handleEditor="handleEditor"
|
||||
@closeInputToolBar="() => changeToolbarDisplayType('none')"
|
||||
@toggleMultipleSelectMode="toggleMultipleSelectMode"
|
||||
/>
|
||||
<div
|
||||
v-if="isNotInGroup"
|
||||
:class="{
|
||||
'tui-chat-leave-group': true,
|
||||
'tui-chat-leave-group-mobile': isMobile,
|
||||
}"
|
||||
>
|
||||
{{ leaveGroupReasonText }}
|
||||
</div>
|
||||
<MultipleSelectPanel
|
||||
v-else-if="isMultipleSelectMode"
|
||||
@oneByOneForwardMessage="oneByOneForwardMessage"
|
||||
@mergeForwardMessage="mergeForwardMessage"
|
||||
@toggleMultipleSelectMode="toggleMultipleSelectMode"
|
||||
/>
|
||||
<template v-else>
|
||||
<MessageInputToolbar
|
||||
v-if="isInputToolbarShow"
|
||||
:class="[
|
||||
'tui-chat-message-input-toolbar',
|
||||
!isPC && 'tui-chat-h5-message-input-toolbar',
|
||||
isUniFrameWork && 'tui-chat-uni-message-input-toolbar'
|
||||
]"
|
||||
:displayType="inputToolbarDisplayType"
|
||||
@insertEmoji="insertEmoji"
|
||||
@changeToolbarDisplayType="changeToolbarDisplayType"
|
||||
@scrollToLatestMessage="scrollToLatestMessage"
|
||||
/>
|
||||
<MessageInput
|
||||
ref="messageInputRef"
|
||||
:class="[
|
||||
'tui-chat-message-input',
|
||||
!isPC && 'tui-chat-h5-message-input',
|
||||
isUniFrameWork && 'tui-chat-uni-message-input',
|
||||
isWeChat && 'tui-chat-wx-message-input',
|
||||
]"
|
||||
:enableAt="featureConfig.InputMention"
|
||||
:isMuted="false"
|
||||
:muteText="TUITranslateService.t('TUIChat.您已被管理员禁言')"
|
||||
:placeholder="TUITranslateService.t('TUIChat.请输入消息')"
|
||||
:inputToolbarDisplayType="inputToolbarDisplayType"
|
||||
@changeToolbarDisplayType="changeToolbarDisplayType"
|
||||
|
||||
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
<!-- Group Management -->
|
||||
<div
|
||||
v-if="!isNotInGroup && !isApp && isUniFrameWork && isGroup && headerExtensionList.length > 0"
|
||||
class="group-profile"
|
||||
@click="handleGroup"
|
||||
>
|
||||
{{ headerExtensionList[0].text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted, onUnmounted, computed } from '../../adapter-vue';
|
||||
import TUIChatEngine, {
|
||||
TUITranslateService,
|
||||
TUIConversationService,
|
||||
TUIStore,
|
||||
StoreName,
|
||||
IMessageModel,
|
||||
IConversationModel,
|
||||
} from '@tencentcloud/chat-uikit-engine';
|
||||
import TUICore, { TUIConstants, ExtensionInfo } from '@tencentcloud/tui-core';
|
||||
import ChatHeader from './chat-header/index.vue';
|
||||
import MessageList from './message-list/index.vue';
|
||||
import MessageInput from './message-input/index.vue';
|
||||
import MultipleSelectPanel from './mulitple-select-panel/index.vue';
|
||||
import Forward from './forward/index.vue';
|
||||
import MessageInputToolbar from './message-input-toolbar/index.vue';
|
||||
import { isPC, isWeChat, isUniFrameWork, isMobile, isApp } from '../../utils/env';
|
||||
import { ToolbarDisplayType } from '../../interface';
|
||||
import TUIChatConfig from './config';
|
||||
// @Start uniapp use Chat only
|
||||
import { onLoad, onUnload,onNavigationBarButtonTap } from '@dcloudio/uni-app';
|
||||
import { initChat, logout } from './entry-chat-only.ts';
|
||||
|
||||
onLoad((options) => {
|
||||
console.dir(options)
|
||||
initChat(options);
|
||||
});
|
||||
|
||||
onUnload(() => {
|
||||
// Whether logout is decided by yourself when the page is unloaded. The default is false.
|
||||
logout(false).then(() => {
|
||||
// Handle success result from promise.then when you set true.
|
||||
}).catch(() => {
|
||||
// handle error
|
||||
});
|
||||
});
|
||||
// @End uniapp use Chat only
|
||||
|
||||
const emits = defineEmits(['closeChat']);
|
||||
const fn = uni.getSystemInfoSync().windowHeight
|
||||
const groupID = ref(undefined);
|
||||
const isGroup = ref(false);
|
||||
const isNotInGroup = ref(false);
|
||||
const notInGroupReason = ref<number>();
|
||||
const currentConversationID = ref("");
|
||||
const isMultipleSelectMode = ref(false);
|
||||
const inputToolbarDisplayType = ref<ToolbarDisplayType>('none');
|
||||
const messageInputRef = ref();
|
||||
const messageListRef = ref<InstanceType<typeof MessageList>>();
|
||||
const headerExtensionList = ref<ExtensionInfo[]>([]);
|
||||
const featureConfig = TUIChatConfig.getFeatureConfig();
|
||||
|
||||
onNavigationBarButtonTap((e) => {
|
||||
if (isGroup.value) {
|
||||
handleGroup();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdate,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdate,
|
||||
});
|
||||
reset();
|
||||
});
|
||||
|
||||
const isInputToolbarShow = computed<boolean>(() => {
|
||||
return isUniFrameWork ? inputToolbarDisplayType.value !== 'none' : true;
|
||||
});
|
||||
|
||||
const leaveGroupReasonText = computed<string>(() => {
|
||||
let text = '';
|
||||
switch (notInGroupReason.value) {
|
||||
case 4:
|
||||
text = TUITranslateService.t('TUIChat.您已被管理员移出群聊');
|
||||
break;
|
||||
case 5:
|
||||
text = TUITranslateService.t('TUIChat.该群聊已被解散');
|
||||
break;
|
||||
case 8:
|
||||
text = TUITranslateService.t('TUIChat.您已退出该群聊');
|
||||
break;
|
||||
default:
|
||||
text = TUITranslateService.t('TUIChat.您已退出该群聊');
|
||||
break;
|
||||
}
|
||||
return text;
|
||||
});
|
||||
|
||||
const reset = () => {
|
||||
TUIConversationService.switchConversation('');
|
||||
};
|
||||
|
||||
const closeChat = (conversationID: string) => {
|
||||
emits('closeChat', conversationID);
|
||||
reset();
|
||||
};
|
||||
|
||||
const insertEmoji = (emojiObj: object) => {
|
||||
messageInputRef.value?.insertEmoji(emojiObj);
|
||||
};
|
||||
|
||||
const handleEditor = (message: IMessageModel, type: string) => {
|
||||
if (!message || !type) return;
|
||||
switch (type) {
|
||||
case 'reference':
|
||||
// todo
|
||||
break;
|
||||
case 'reply':
|
||||
// todo
|
||||
break;
|
||||
case 'reedit':
|
||||
if (message?.payload?.text) {
|
||||
messageInputRef?.value?.reEdit(message?.payload?.text);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const handleGroup = () => {
|
||||
headerExtensionList.value[0].listener.onClicked({ groupID: groupID.value });
|
||||
uni.navigateTo({
|
||||
url: `/TUIKit/components/TUIGroup/index`
|
||||
});
|
||||
};
|
||||
|
||||
function changeToolbarDisplayType(type: ToolbarDisplayType) {
|
||||
inputToolbarDisplayType.value = inputToolbarDisplayType.value === type ? 'none' : type;
|
||||
if (inputToolbarDisplayType.value !== 'none' && isUniFrameWork) {
|
||||
uni.$emit('scroll-to-bottom');
|
||||
}
|
||||
}
|
||||
|
||||
function scrollToLatestMessage() {
|
||||
messageListRef.value?.scrollToLatestMessage();
|
||||
}
|
||||
|
||||
function toggleMultipleSelectMode(visible?: boolean) {
|
||||
isMultipleSelectMode.value = visible === undefined ? !isMultipleSelectMode.value : visible;
|
||||
}
|
||||
|
||||
function mergeForwardMessage() {
|
||||
messageListRef.value?.mergeForwardMessage();
|
||||
}
|
||||
|
||||
function oneByOneForwardMessage() {
|
||||
messageListRef.value?.oneByOneForwardMessage();
|
||||
}
|
||||
|
||||
function updateUIUserNotInGroup(conversation: IConversationModel) {
|
||||
if (conversation?.operationType > 0) {
|
||||
headerExtensionList.value = [];
|
||||
isNotInGroup.value = true;
|
||||
/**
|
||||
* 4 - be removed from the group
|
||||
* 5 - group is dismissed
|
||||
* 8 - quit group
|
||||
*/
|
||||
notInGroupReason.value = conversation?.operationType;
|
||||
} else {
|
||||
isNotInGroup.value = false;
|
||||
notInGroupReason.value = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function onCurrentConversationUpdate(conversation: IConversationModel) {
|
||||
updateUIUserNotInGroup(conversation);
|
||||
// return when currentConversation is null
|
||||
if (!conversation) {
|
||||
return;
|
||||
}
|
||||
// return when currentConversationID.value is the same as conversation.conversationID.
|
||||
if (currentConversationID.value === conversation?.conversationID) {
|
||||
return;
|
||||
}
|
||||
|
||||
isGroup.value = false;
|
||||
let conversationType = TUIChatEngine.TYPES.CONV_C2C;
|
||||
const conversationID = conversation.conversationID;
|
||||
if (conversationID.startsWith(TUIChatEngine.TYPES.CONV_GROUP)) {
|
||||
conversationType = TUIChatEngine.TYPES.CONV_GROUP;
|
||||
isGroup.value = true;
|
||||
groupID.value = conversationID.replace(TUIChatEngine.TYPES.CONV_GROUP, '');
|
||||
}
|
||||
|
||||
headerExtensionList.value = [];
|
||||
isMultipleSelectMode.value = false;
|
||||
// Initialize chatType
|
||||
TUIChatConfig.setChatType(conversationType);
|
||||
// While converstaion change success, notify callkit and roomkit、or other components.
|
||||
TUICore.notifyEvent(TUIConstants.TUIChat.EVENT.CHAT_STATE_CHANGED, TUIConstants.TUIChat.EVENT_SUB_KEY.CHAT_OPENED, { groupID: groupID.value });
|
||||
// The TUICustomerServicePlugin plugin determines if the current conversation is a customer service conversation, then sets chatType and activates the conversation.
|
||||
TUICore.callService({
|
||||
serviceName: TUIConstants.TUICustomerServicePlugin.SERVICE.NAME,
|
||||
method: TUIConstants.TUICustomerServicePlugin.SERVICE.METHOD.ACTIVE_CONVERSATION,
|
||||
params: { conversationID: conversationID },
|
||||
});
|
||||
// When open chat in room, close main chat ui and reset theme.
|
||||
if (TUIChatConfig.getChatType() === TUIConstants.TUIChat.TYPE.ROOM) {
|
||||
if (TUIChatConfig.getFeatureConfig(TUIConstants.TUIChat.FEATURE.InputVoice) === true) {
|
||||
TUIChatConfig.setTheme('light');
|
||||
currentConversationID.value = '';
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Get chat header extensions
|
||||
if (TUIChatConfig.getChatType() === TUIConstants.TUIChat.TYPE.GROUP) {
|
||||
headerExtensionList.value = TUICore.getExtensionList(TUIConstants.TUIChat.EXTENSION.CHAT_HEADER.EXT_ID);
|
||||
}
|
||||
TUIStore.update(StoreName.CUSTOM, 'activeConversation', conversationID);
|
||||
currentConversationID.value = conversationID;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss" src="./style/index.scss">
|
||||
.chat{
|
||||
width: 100% !important;
|
||||
height: 100vh !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@ -1,243 +1,243 @@
|
||||
<template>
|
||||
<div :class="['message-input', !isPC && 'message-input-h5']">
|
||||
<div class="audio-main-content-line">
|
||||
<MessageInputAudio
|
||||
v-if="(isWeChat || isApp) && isRenderVoice"
|
||||
:class="{
|
||||
'message-input-wx-audio-open': displayType === 'audio',
|
||||
}"
|
||||
:isEnableAudio="displayType === 'audio'"
|
||||
@changeDisplayType="changeDisplayType"
|
||||
/>
|
||||
<MessageInputEditor
|
||||
v-show="displayType === 'editor'"
|
||||
ref="editor"
|
||||
class="message-input-editor"
|
||||
:placeholder="props.placeholder"
|
||||
:isMuted="props.isMuted"
|
||||
:muteText="props.muteText"
|
||||
:enableInput="props.enableInput"
|
||||
:enableAt="props.enableAt"
|
||||
:enableTyping="props.enableTyping"
|
||||
:isGroup="isGroup"
|
||||
@onTyping="onTyping"
|
||||
@onAt="onAt"
|
||||
@onFocus="onFocus"
|
||||
/>
|
||||
<MessageInputAt
|
||||
v-if="props.enableAt"
|
||||
ref="messageInputAtRef"
|
||||
@insertAt="insertAt"
|
||||
@onAtListOpen="onAtListOpen"
|
||||
/>
|
||||
<Icon
|
||||
v-if="isRenderEmojiPicker"
|
||||
class="icon icon-face"
|
||||
:file="faceIcon"
|
||||
:size="'23px'"
|
||||
:hotAreaSize="'3px'"
|
||||
@onClick="changeToolbarDisplayType('emojiPicker')"
|
||||
/>
|
||||
<Icon
|
||||
v-if="isRenderMore"
|
||||
class="icon icon-more"
|
||||
:file="moreIcon"
|
||||
:size="'23px'"
|
||||
:hotAreaSize="'3px'"
|
||||
@onClick="changeToolbarDisplayType('tools')"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<MessageQuote
|
||||
:style="{minWidth: 0}"
|
||||
:displayType="displayType"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TUIChatEngine, {
|
||||
TUIStore,
|
||||
StoreName,
|
||||
IMessageModel,
|
||||
IConversationModel,
|
||||
} from '@tencentcloud/chat-uikit-engine';
|
||||
import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import MessageInputEditor from './message-input-editor.vue';
|
||||
import MessageInputAt from './message-input-at/index.vue';
|
||||
import MessageInputAudio from './message-input-audio.vue';
|
||||
import MessageQuote from './message-input-quote/index.vue';
|
||||
import Icon from '../../common/Icon.vue';
|
||||
import faceIcon from '../../../assets/icon/face-uni.png';
|
||||
import moreIcon from '../../../assets/icon/more-uni.png';
|
||||
import { isPC, isH5, isWeChat, isApp } from '../../../utils/env';
|
||||
import { sendTyping } from '../utils/sendMessage';
|
||||
import { ToolbarDisplayType, InputDisplayType } from '../../../interface';
|
||||
import TUIChatConfig from '../config';
|
||||
|
||||
interface IProps {
|
||||
placeholder: string;
|
||||
isMuted?: boolean;
|
||||
muteText?: string;
|
||||
enableInput?: boolean;
|
||||
enableAt?: boolean;
|
||||
enableTyping?: boolean;
|
||||
replyOrReference?: Record<string, any>;
|
||||
inputToolbarDisplayType: ToolbarDisplayType;
|
||||
}
|
||||
interface IEmits {
|
||||
(e: 'changeToolbarDisplayType', displayType: ToolbarDisplayType): void;
|
||||
}
|
||||
|
||||
const emits = defineEmits<IEmits>();
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
placeholder: 'this is placeholder',
|
||||
replyOrReference: () => ({}),
|
||||
isMuted: true,
|
||||
muteText: '',
|
||||
enableInput: true,
|
||||
enableAt: true,
|
||||
enableTyping: true,
|
||||
inputToolbarDisplayType: 'none',
|
||||
});
|
||||
|
||||
const editor = ref();
|
||||
const messageInputAtRef = ref();
|
||||
const currentConversation = ref<IConversationModel>();
|
||||
const isGroup = ref<boolean>(false);
|
||||
const displayType = ref<InputDisplayType>('editor');
|
||||
const featureConfig = TUIChatConfig.getFeatureConfig();
|
||||
const isRenderVoice = ref<boolean>(featureConfig.InputVoice);
|
||||
const isRenderEmojiPicker = ref<boolean>(featureConfig.InputEmoji || featureConfig.InputStickers);
|
||||
const isRenderMore = ref<boolean>(featureConfig.InputImage || featureConfig.InputVideo || featureConfig.InputEvaluation || featureConfig.InputQuickReplies);
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.unwatch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
watch(() => props.inputToolbarDisplayType, (newVal: ToolbarDisplayType) => {
|
||||
if (newVal !== 'none') {
|
||||
changeDisplayType('editor');
|
||||
}
|
||||
});
|
||||
|
||||
function changeDisplayType(display: InputDisplayType) {
|
||||
displayType.value = display;
|
||||
if (display === 'audio') {
|
||||
emits('changeToolbarDisplayType', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
function changeToolbarDisplayType(displayType: ToolbarDisplayType) {
|
||||
emits('changeToolbarDisplayType', displayType);
|
||||
}
|
||||
|
||||
const onTyping = (inputContentEmpty: boolean, inputBlur: boolean) => {
|
||||
sendTyping(inputContentEmpty, inputBlur);
|
||||
};
|
||||
|
||||
const onAt = (show: boolean) => {
|
||||
messageInputAtRef?.value?.toggleAtList(show);
|
||||
};
|
||||
|
||||
const onFocus = () => {
|
||||
// if (isH5) {
|
||||
emits('changeToolbarDisplayType', 'none');
|
||||
// }
|
||||
// 新增隐藏加号控制显示内容的逻辑
|
||||
// emits('changeToolbarDisplayType', 'none');
|
||||
};
|
||||
|
||||
const insertEmoji = (emoji: any) => {
|
||||
editor?.value?.addEmoji && editor?.value?.addEmoji(emoji);
|
||||
};
|
||||
|
||||
const insertAt = (atInfo: any) => {
|
||||
editor?.value?.insertAt && editor?.value?.insertAt(atInfo);
|
||||
};
|
||||
|
||||
const onAtListOpen = () => {
|
||||
editor?.value?.blur && editor?.value?.blur();
|
||||
};
|
||||
|
||||
const reEdit = (content: any) => {
|
||||
editor?.value?.resetEditor();
|
||||
editor?.value?.setEditorContent(content);
|
||||
};
|
||||
|
||||
function onCurrentConversationUpdated(conversation: IConversationModel) {
|
||||
currentConversation.value = conversation;
|
||||
isGroup.value = currentConversation.value?.type === TUIChatEngine.TYPES.CONV_GROUP;
|
||||
}
|
||||
|
||||
function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) {
|
||||
// switch text input mode when there is a quote message
|
||||
if (options?.message && options?.type === 'quote') {
|
||||
changeDisplayType('editor');
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
insertEmoji,
|
||||
reEdit,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../../assets/styles/common";
|
||||
|
||||
:not(not) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
background: #ebf0f6;
|
||||
|
||||
&-h5 {
|
||||
padding: 10px 10px 15px;
|
||||
}
|
||||
|
||||
&-editor {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
&-wx-audio-open {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-main-content-line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div :class="['message-input', !isPC && 'message-input-h5']">
|
||||
<div class="audio-main-content-line">
|
||||
<MessageInputAudio
|
||||
v-if="(isWeChat || isApp) && isRenderVoice"
|
||||
:class="{
|
||||
'message-input-wx-audio-open': displayType === 'audio',
|
||||
}"
|
||||
:isEnableAudio="displayType === 'audio'"
|
||||
@changeDisplayType="changeDisplayType"
|
||||
/>
|
||||
<MessageInputEditor
|
||||
v-show="displayType === 'editor'"
|
||||
ref="editor"
|
||||
class="message-input-editor"
|
||||
:placeholder="props.placeholder"
|
||||
:isMuted="props.isMuted"
|
||||
:muteText="props.muteText"
|
||||
:enableInput="props.enableInput"
|
||||
:enableAt="props.enableAt"
|
||||
:enableTyping="props.enableTyping"
|
||||
:isGroup="isGroup"
|
||||
@onTyping="onTyping"
|
||||
@onAt="onAt"
|
||||
@onFocus="onFocus"
|
||||
/>
|
||||
<MessageInputAt
|
||||
v-if="props.enableAt"
|
||||
ref="messageInputAtRef"
|
||||
@insertAt="insertAt"
|
||||
@onAtListOpen="onAtListOpen"
|
||||
/>
|
||||
<Icon
|
||||
v-if="isRenderEmojiPicker"
|
||||
class="icon icon-face"
|
||||
:file="faceIcon"
|
||||
:size="'23px'"
|
||||
:hotAreaSize="'3px'"
|
||||
@onClick="changeToolbarDisplayType('emojiPicker')"
|
||||
/>
|
||||
<Icon
|
||||
v-if="isRenderMore"
|
||||
class="icon icon-more"
|
||||
:file="moreIcon"
|
||||
:size="'23px'"
|
||||
:hotAreaSize="'3px'"
|
||||
@onClick="changeToolbarDisplayType('tools')"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<MessageQuote
|
||||
:style="{minWidth: 0}"
|
||||
:displayType="displayType"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TUIChatEngine, {
|
||||
TUIStore,
|
||||
StoreName,
|
||||
IMessageModel,
|
||||
IConversationModel,
|
||||
} from '@tencentcloud/chat-uikit-engine';
|
||||
import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import MessageInputEditor from './message-input-editor.vue';
|
||||
import MessageInputAt from './message-input-at/index.vue';
|
||||
import MessageInputAudio from './message-input-audio.vue';
|
||||
import MessageQuote from './message-input-quote/index.vue';
|
||||
import Icon from '../../common/Icon.vue';
|
||||
import faceIcon from '../../../assets/icon/face-uni.png';
|
||||
import moreIcon from '../../../assets/icon/more-uni.png';
|
||||
import { isPC, isH5, isWeChat, isApp } from '../../../utils/env';
|
||||
import { sendTyping } from '../utils/sendMessage';
|
||||
import { ToolbarDisplayType, InputDisplayType } from '../../../interface';
|
||||
import TUIChatConfig from '../config';
|
||||
|
||||
interface IProps {
|
||||
placeholder: string;
|
||||
isMuted?: boolean;
|
||||
muteText?: string;
|
||||
enableInput?: boolean;
|
||||
enableAt?: boolean;
|
||||
enableTyping?: boolean;
|
||||
replyOrReference?: Record<string, any>;
|
||||
inputToolbarDisplayType: ToolbarDisplayType;
|
||||
}
|
||||
interface IEmits {
|
||||
(e: 'changeToolbarDisplayType', displayType: ToolbarDisplayType): void;
|
||||
}
|
||||
|
||||
const emits = defineEmits<IEmits>();
|
||||
const props = withDefaults(defineProps<IProps>(), {
|
||||
placeholder: 'this is placeholder',
|
||||
replyOrReference: () => ({}),
|
||||
isMuted: true,
|
||||
muteText: '',
|
||||
enableInput: true,
|
||||
enableAt: true,
|
||||
enableTyping: true,
|
||||
inputToolbarDisplayType: 'none',
|
||||
});
|
||||
|
||||
const editor = ref();
|
||||
const messageInputAtRef = ref();
|
||||
const currentConversation = ref<IConversationModel>();
|
||||
const isGroup = ref<boolean>(false);
|
||||
const displayType = ref<InputDisplayType>('editor');
|
||||
const featureConfig = TUIChatConfig.getFeatureConfig();
|
||||
const isRenderVoice = ref<boolean>(featureConfig.InputVoice);
|
||||
const isRenderEmojiPicker = ref<boolean>(featureConfig.InputEmoji || featureConfig.InputStickers);
|
||||
const isRenderMore = ref<boolean>(featureConfig.InputImage || featureConfig.InputVideo || featureConfig.InputEvaluation || featureConfig.InputQuickReplies);
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.unwatch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
watch(() => props.inputToolbarDisplayType, (newVal: ToolbarDisplayType) => {
|
||||
if (newVal !== 'none') {
|
||||
changeDisplayType('editor');
|
||||
}
|
||||
});
|
||||
|
||||
function changeDisplayType(display: InputDisplayType) {
|
||||
displayType.value = display;
|
||||
if (display === 'audio') {
|
||||
emits('changeToolbarDisplayType', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
function changeToolbarDisplayType(displayType: ToolbarDisplayType) {
|
||||
emits('changeToolbarDisplayType', displayType);
|
||||
}
|
||||
|
||||
const onTyping = (inputContentEmpty: boolean, inputBlur: boolean) => {
|
||||
sendTyping(inputContentEmpty, inputBlur);
|
||||
};
|
||||
|
||||
const onAt = (show: boolean) => {
|
||||
messageInputAtRef?.value?.toggleAtList(show);
|
||||
};
|
||||
|
||||
const onFocus = () => {
|
||||
// if (isH5) {
|
||||
emits('changeToolbarDisplayType', 'none');
|
||||
// }
|
||||
// 新增隐藏加号控制显示内容的逻辑
|
||||
// emits('changeToolbarDisplayType', 'none');
|
||||
};
|
||||
|
||||
const insertEmoji = (emoji: any) => {
|
||||
editor?.value?.addEmoji && editor?.value?.addEmoji(emoji);
|
||||
};
|
||||
|
||||
const insertAt = (atInfo: any) => {
|
||||
editor?.value?.insertAt && editor?.value?.insertAt(atInfo);
|
||||
};
|
||||
|
||||
const onAtListOpen = () => {
|
||||
editor?.value?.blur && editor?.value?.blur();
|
||||
};
|
||||
|
||||
const reEdit = (content: any) => {
|
||||
editor?.value?.resetEditor();
|
||||
editor?.value?.setEditorContent(content);
|
||||
};
|
||||
|
||||
function onCurrentConversationUpdated(conversation: IConversationModel) {
|
||||
currentConversation.value = conversation;
|
||||
isGroup.value = currentConversation.value?.type === TUIChatEngine.TYPES.CONV_GROUP;
|
||||
}
|
||||
|
||||
function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) {
|
||||
// switch text input mode when there is a quote message
|
||||
if (options?.message && options?.type === 'quote') {
|
||||
changeDisplayType('editor');
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
insertEmoji,
|
||||
reEdit,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../../assets/styles/common";
|
||||
|
||||
:not(not) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.message-input {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: none;
|
||||
overflow: hidden;
|
||||
background: #ebf0f6;
|
||||
|
||||
&-h5 {
|
||||
padding: 10px 10px 15px;
|
||||
}
|
||||
|
||||
&-editor {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
&-wx-audio-open {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.audio-main-content-line {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,285 +1,285 @@
|
||||
<template>
|
||||
<div
|
||||
:class="{
|
||||
'message-input-container': true,
|
||||
'message-input-container-h5': !isPC,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-if="props.isMuted"
|
||||
class="message-input-mute"
|
||||
>
|
||||
{{ props.muteText }}
|
||||
</div>
|
||||
<input
|
||||
id="editor"
|
||||
ref="inputRef"
|
||||
v-model="inputText"
|
||||
:adjust-position="true"
|
||||
cursor-spacing="20"
|
||||
confirm-type="send"
|
||||
:confirm-hold="true"
|
||||
maxlength="140"
|
||||
type="text"
|
||||
placeholder-class="input-placeholder"
|
||||
class="message-input-area"
|
||||
:placeholder="props.placeholder"
|
||||
auto-blur
|
||||
@confirm="handleSendMessage"
|
||||
@input="onInput"
|
||||
@blur="onBlur"
|
||||
@focus="onFocus"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import { TUIStore, StoreName, IConversationModel, IMessageModel } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import DraftManager from '../utils/conversationDraft';
|
||||
import { transformTextWithEmojiNamesToKeys } from '../emoji-config';
|
||||
import { isPC } from '../../../utils/env';
|
||||
import { sendMessages } from '../utils/sendMessage';
|
||||
import { ISendMessagePayload } from '../../../interface';
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'this is placeholder',
|
||||
},
|
||||
replayOrReferenceMessage: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
required: false,
|
||||
},
|
||||
isMuted: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
muteText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
enableInput: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableAt: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableTyping: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isGroup: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['onTyping', 'onFocus', 'onAt']);
|
||||
const inputText = ref('');
|
||||
const inputRef = ref();
|
||||
const inputBlur = ref(true);
|
||||
const inputContentEmpty = ref(true);
|
||||
const allInsertedAtInfo = new Map();
|
||||
const currentConversation = ref<IConversationModel>();
|
||||
const currentConversationID = ref<string>('');
|
||||
const currentQuoteMessage = ref<{ message: IMessageModel; type: string }>();
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
|
||||
uni.$on('insert-emoji', (data) => {
|
||||
inputText.value += data?.emoji?.name;
|
||||
});
|
||||
|
||||
uni.$on('send-message-in-emoji-picker', () => {
|
||||
handleSendMessage();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (currentConversationID.value) {
|
||||
DraftManager.setStore(currentConversationID.value, inputText.value, inputText.value, currentQuoteMessage.value);
|
||||
}
|
||||
|
||||
uni.$off('insertEmoji');
|
||||
uni.$off('send-message-in-emoji-picker');
|
||||
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.unwatch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
|
||||
reset();
|
||||
});
|
||||
|
||||
const handleSendMessage = () => {
|
||||
const messageList = getEditorContent();
|
||||
resetEditor();
|
||||
sendMessages(messageList as any, currentConversation.value!);
|
||||
};
|
||||
|
||||
const insertAt = (atInfo: any) => {
|
||||
if (!allInsertedAtInfo?.has(atInfo?.id)) {
|
||||
allInsertedAtInfo?.set(atInfo?.id, atInfo?.label);
|
||||
}
|
||||
inputText.value += atInfo?.label;
|
||||
};
|
||||
|
||||
const getEditorContent = () => {
|
||||
let text = inputText.value;
|
||||
text = transformTextWithEmojiNamesToKeys(text);
|
||||
const atUserList: string[] = [];
|
||||
allInsertedAtInfo?.forEach((value: string, key: string) => {
|
||||
if (text?.includes('@' + value)) {
|
||||
atUserList.push(key);
|
||||
}
|
||||
});
|
||||
const payload: ISendMessagePayload = {
|
||||
text,
|
||||
};
|
||||
if (atUserList?.length) {
|
||||
payload.atUserList = atUserList;
|
||||
}
|
||||
return [
|
||||
{
|
||||
type: 'text',
|
||||
payload,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const resetEditor = () => {
|
||||
inputText.value = '';
|
||||
inputContentEmpty.value = true;
|
||||
allInsertedAtInfo?.clear();
|
||||
};
|
||||
|
||||
const setEditorContent = (content: any) => {
|
||||
inputText.value = content;
|
||||
};
|
||||
|
||||
const onBlur = () => {
|
||||
inputBlur.value = true;
|
||||
};
|
||||
|
||||
const onFocus = (e: any) => {
|
||||
inputBlur.value = false;
|
||||
emits('onFocus', e?.detail?.height);
|
||||
};
|
||||
|
||||
const isEditorContentEmpty = () => {
|
||||
inputContentEmpty.value = inputText?.value?.length ? false : true;
|
||||
};
|
||||
|
||||
const onInput = (e: any) => {
|
||||
// uni-app recognizes mention messages
|
||||
const text = e?.detail?.value;
|
||||
isEditorContentEmpty();
|
||||
if (props.isGroup && (text.endsWith('@') || text.endsWith('@\n'))) {
|
||||
// TUIGlobal?.hideKeyboard();
|
||||
emits('onAt', true);
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => [inputContentEmpty.value, inputBlur.value],
|
||||
(newVal: any, oldVal: any) => {
|
||||
if (newVal !== oldVal) {
|
||||
emits('onTyping', inputContentEmpty.value, inputBlur.value);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
);
|
||||
|
||||
function onCurrentConversationUpdated(conversation: IConversationModel) {
|
||||
const prevConversationID = currentConversationID.value;
|
||||
currentConversation.value = conversation;
|
||||
currentConversationID.value = conversation?.conversationID;
|
||||
if (prevConversationID !== currentConversationID.value) {
|
||||
if (prevConversationID) {
|
||||
DraftManager.setStore(
|
||||
prevConversationID,
|
||||
inputText.value,
|
||||
inputText.value,
|
||||
currentQuoteMessage.value,
|
||||
);
|
||||
}
|
||||
resetEditor();
|
||||
if (currentConversationID.value) {
|
||||
DraftManager.getStore(currentConversationID.value, setEditorContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) {
|
||||
currentQuoteMessage.value = options;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
inputBlur.value = true;
|
||||
currentConversation.value = null;
|
||||
currentConversationID.value = '';
|
||||
currentQuoteMessage.value = null;
|
||||
resetEditor();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
insertAt,
|
||||
resetEditor,
|
||||
setEditorContent,
|
||||
getEditorContent,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../../assets/styles/common";
|
||||
|
||||
.message-input-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 3px 10px 10px;
|
||||
overflow: hidden;
|
||||
|
||||
&-h5 {
|
||||
flex: 1;
|
||||
height: auto;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 7px 0 7px 10px;
|
||||
font-size: 16px !important;
|
||||
max-height: 86px;
|
||||
}
|
||||
|
||||
.message-input-mute {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-input-area {
|
||||
flex: 1;
|
||||
overflow-y: scroll;
|
||||
min-height: 25px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div
|
||||
:class="{
|
||||
'message-input-container': true,
|
||||
'message-input-container-h5': !isPC,
|
||||
}"
|
||||
>
|
||||
<div
|
||||
v-if="props.isMuted"
|
||||
class="message-input-mute"
|
||||
>
|
||||
{{ props.muteText }}
|
||||
</div>
|
||||
<input
|
||||
id="editor"
|
||||
ref="inputRef"
|
||||
v-model="inputText"
|
||||
:adjust-position="true"
|
||||
cursor-spacing="20"
|
||||
confirm-type="send"
|
||||
:confirm-hold="true"
|
||||
maxlength="140"
|
||||
type="text"
|
||||
placeholder-class="input-placeholder"
|
||||
class="message-input-area"
|
||||
:placeholder="props.placeholder"
|
||||
auto-blur
|
||||
@confirm="handleSendMessage"
|
||||
@input="onInput"
|
||||
@blur="onBlur"
|
||||
@focus="onFocus"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import { TUIStore, StoreName, IConversationModel, IMessageModel } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import DraftManager from '../utils/conversationDraft';
|
||||
import { transformTextWithEmojiNamesToKeys } from '../emoji-config';
|
||||
import { isPC } from '../../../utils/env';
|
||||
import { sendMessages } from '../utils/sendMessage';
|
||||
import { ISendMessagePayload } from '../../../interface';
|
||||
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: 'this is placeholder',
|
||||
},
|
||||
replayOrReferenceMessage: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
required: false,
|
||||
},
|
||||
isMuted: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
muteText: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
enableInput: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableAt: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableTyping: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
isGroup: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emits = defineEmits(['onTyping', 'onFocus', 'onAt']);
|
||||
const inputText = ref('');
|
||||
const inputRef = ref();
|
||||
const inputBlur = ref(true);
|
||||
const inputContentEmpty = ref(true);
|
||||
const allInsertedAtInfo = new Map();
|
||||
const currentConversation = ref<IConversationModel>();
|
||||
const currentConversationID = ref<string>('');
|
||||
const currentQuoteMessage = ref<{ message: IMessageModel; type: string }>();
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
|
||||
uni.$on('insert-emoji', (data) => {
|
||||
inputText.value += data?.emoji?.name;
|
||||
});
|
||||
|
||||
uni.$on('send-message-in-emoji-picker', () => {
|
||||
handleSendMessage();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (currentConversationID.value) {
|
||||
DraftManager.setStore(currentConversationID.value, inputText.value, inputText.value, currentQuoteMessage.value);
|
||||
}
|
||||
|
||||
uni.$off('insertEmoji');
|
||||
uni.$off('send-message-in-emoji-picker');
|
||||
|
||||
TUIStore.unwatch(StoreName.CONV, {
|
||||
currentConversation: onCurrentConversationUpdated,
|
||||
});
|
||||
|
||||
TUIStore.unwatch(StoreName.CHAT, {
|
||||
quoteMessage: onQuoteMessageUpdated,
|
||||
});
|
||||
|
||||
reset();
|
||||
});
|
||||
|
||||
const handleSendMessage = () => {
|
||||
const messageList = getEditorContent();
|
||||
resetEditor();
|
||||
sendMessages(messageList as any, currentConversation.value!);
|
||||
};
|
||||
|
||||
const insertAt = (atInfo: any) => {
|
||||
if (!allInsertedAtInfo?.has(atInfo?.id)) {
|
||||
allInsertedAtInfo?.set(atInfo?.id, atInfo?.label);
|
||||
}
|
||||
inputText.value += atInfo?.label;
|
||||
};
|
||||
|
||||
const getEditorContent = () => {
|
||||
let text = inputText.value;
|
||||
text = transformTextWithEmojiNamesToKeys(text);
|
||||
const atUserList: string[] = [];
|
||||
allInsertedAtInfo?.forEach((value: string, key: string) => {
|
||||
if (text?.includes('@' + value)) {
|
||||
atUserList.push(key);
|
||||
}
|
||||
});
|
||||
const payload: ISendMessagePayload = {
|
||||
text,
|
||||
};
|
||||
if (atUserList?.length) {
|
||||
payload.atUserList = atUserList;
|
||||
}
|
||||
return [
|
||||
{
|
||||
type: 'text',
|
||||
payload,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const resetEditor = () => {
|
||||
inputText.value = '';
|
||||
inputContentEmpty.value = true;
|
||||
allInsertedAtInfo?.clear();
|
||||
};
|
||||
|
||||
const setEditorContent = (content: any) => {
|
||||
inputText.value = content;
|
||||
};
|
||||
|
||||
const onBlur = () => {
|
||||
inputBlur.value = true;
|
||||
};
|
||||
|
||||
const onFocus = (e: any) => {
|
||||
inputBlur.value = false;
|
||||
emits('onFocus', e?.detail?.height);
|
||||
};
|
||||
|
||||
const isEditorContentEmpty = () => {
|
||||
inputContentEmpty.value = inputText?.value?.length ? false : true;
|
||||
};
|
||||
|
||||
const onInput = (e: any) => {
|
||||
// uni-app recognizes mention messages
|
||||
const text = e?.detail?.value;
|
||||
isEditorContentEmpty();
|
||||
if (props.isGroup && (text.endsWith('@') || text.endsWith('@\n'))) {
|
||||
// TUIGlobal?.hideKeyboard();
|
||||
emits('onAt', true);
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => [inputContentEmpty.value, inputBlur.value],
|
||||
(newVal: any, oldVal: any) => {
|
||||
if (newVal !== oldVal) {
|
||||
emits('onTyping', inputContentEmpty.value, inputBlur.value);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
deep: true,
|
||||
},
|
||||
);
|
||||
|
||||
function onCurrentConversationUpdated(conversation: IConversationModel) {
|
||||
const prevConversationID = currentConversationID.value;
|
||||
currentConversation.value = conversation;
|
||||
currentConversationID.value = conversation?.conversationID;
|
||||
if (prevConversationID !== currentConversationID.value) {
|
||||
if (prevConversationID) {
|
||||
DraftManager.setStore(
|
||||
prevConversationID,
|
||||
inputText.value,
|
||||
inputText.value,
|
||||
currentQuoteMessage.value,
|
||||
);
|
||||
}
|
||||
resetEditor();
|
||||
if (currentConversationID.value) {
|
||||
DraftManager.getStore(currentConversationID.value, setEditorContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) {
|
||||
currentQuoteMessage.value = options;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
inputBlur.value = true;
|
||||
currentConversation.value = null;
|
||||
currentConversationID.value = '';
|
||||
currentQuoteMessage.value = null;
|
||||
resetEditor();
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
insertAt,
|
||||
resetEditor,
|
||||
setEditorContent,
|
||||
getEditorContent,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "../../../assets/styles/common";
|
||||
|
||||
.message-input-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
padding: 3px 10px 10px;
|
||||
overflow: hidden;
|
||||
|
||||
&-h5 {
|
||||
flex: 1;
|
||||
height: auto;
|
||||
background: #fff;
|
||||
border-radius: 10px;
|
||||
padding: 7px 0 7px 10px;
|
||||
font-size: 16px !important;
|
||||
max-height: 86px;
|
||||
}
|
||||
|
||||
.message-input-mute {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.message-input-area {
|
||||
flex: 1;
|
||||
overflow-y: scroll;
|
||||
min-height: 25px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,430 +1,430 @@
|
||||
<template>
|
||||
<div
|
||||
:style="{height: '100%'}"
|
||||
v-if="typeof contactInfoData === 'object' && Object.keys(contactInfoData).length"
|
||||
:class="['tui-contact-info', !isPC && 'tui-contact-info-h5']"
|
||||
>
|
||||
<div
|
||||
v-if="!isPC"
|
||||
:class="[
|
||||
'tui-contact-info-header',
|
||||
!isPC && 'tui-contact-info-h5-header',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-header-icon',
|
||||
!isPC && 'tui-contact-info-h5-header-icon',
|
||||
]"
|
||||
@click="resetContactSearchingUIData"
|
||||
>
|
||||
<Icon :file="backSVG" />
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-header-title',
|
||||
!isPC && 'tui-contact-info-h5-header-title',
|
||||
]"
|
||||
>
|
||||
{{ TUITranslateService.t("TUIContact.添加好友/群聊") }}
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['tui-contact-info-basic', !isPC && 'tui-contact-info-h5-basic']">
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-basic-text',
|
||||
!isPC && 'tui-contact-info-h5-basic-text',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-basic-text-name',
|
||||
!isPC && 'tui-contact-info-h5-basic-text-name',
|
||||
]"
|
||||
>
|
||||
{{ generateContactInfoName(contactInfoData) }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in contactInfoBasicList"
|
||||
:key="item.label"
|
||||
:class="[
|
||||
'tui-contact-info-basic-text-other',
|
||||
!isPC && 'tui-contact-info-h5-basic-text-other',
|
||||
]"
|
||||
>
|
||||
{{
|
||||
`${TUITranslateService.t(`TUIContact.${item.label}`)}:
|
||||
${item.data}`
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
:class="[
|
||||
'tui-contact-info-basic-avatar',
|
||||
!isPC && 'tui-contact-info-h5-basic-avatar',
|
||||
]"
|
||||
:src="generateAvatar(contactInfoData)"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
v-if="contactInfoMoreList[0]"
|
||||
:class="['tui-contact-info-more', !isPC && 'tui-contact-info-h5-more']"
|
||||
>
|
||||
<div
|
||||
v-for="item in contactInfoMoreList"
|
||||
:key="item.key"
|
||||
:class="[
|
||||
'tui-contact-info-more-item',
|
||||
!isPC && 'tui-contact-info-h5-more-item',
|
||||
item.labelPosition === CONTACT_INFO_LABEL_POSITION.TOP
|
||||
? 'tui-contact-info-more-item-top'
|
||||
: 'tui-contact-info-more-item-left',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-more-item-label',
|
||||
!isPC && 'tui-contact-info-h5-more-item-label',
|
||||
]"
|
||||
>
|
||||
{{ `${TUITranslateService.t(`TUIContact.${item.label}`)}` }}
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
v-if="!item.editing"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-text',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-text',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-text-data',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-text-data',
|
||||
]"
|
||||
>
|
||||
{{ item.data }}
|
||||
</div>
|
||||
<div
|
||||
v-if="item.editable"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-text-icon',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-text-icon',
|
||||
]"
|
||||
@click="setEditing(item)"
|
||||
>
|
||||
<Icon
|
||||
:file="editSVG"
|
||||
width="14px"
|
||||
height="14px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.INPUT"
|
||||
v-model="item.data"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-input',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-input',
|
||||
]"
|
||||
type="text"
|
||||
@confirm="onContactInfoEmitSubmit(item)"
|
||||
@keyup.enter="onContactInfoEmitSubmit(item)"
|
||||
>
|
||||
<textarea
|
||||
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.TEXTAREA"
|
||||
v-model="item.data"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-textarea',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-textarea',
|
||||
]"
|
||||
confirm-type="done"
|
||||
/>
|
||||
<div
|
||||
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.SWITCH"
|
||||
@click="onContactInfoEmitSubmit(item)"
|
||||
>
|
||||
<SwitchBar :value="item.data" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-button',
|
||||
!isPC && 'tui-contact-info-h5-button',
|
||||
]"
|
||||
>
|
||||
<button
|
||||
v-for="item in contactInfoButtonList"
|
||||
:key="item.key"
|
||||
:class="[
|
||||
'tui-contact-info-button-item',
|
||||
!isPC && 'tui-contact-info-h5-button-item',
|
||||
item.type === CONTACT_INFO_BUTTON_TYPE.CANCEL
|
||||
? `tui-contact-info-button-item-cancel`
|
||||
: `tui-contact-info-button-item-submit`,
|
||||
]"
|
||||
@click="onContactInfoButtonClicked(item)"
|
||||
>
|
||||
{{ TUITranslateService.t(`TUIContact.${item.label}`) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TUIChatEngine, {
|
||||
TUIStore,
|
||||
StoreName,
|
||||
TUITranslateService,
|
||||
IGroupModel,
|
||||
Friend,
|
||||
FriendApplication,
|
||||
} from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import { ref, computed, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import { isPC } from '../../../utils/env';
|
||||
|
||||
import {
|
||||
generateAvatar,
|
||||
generateContactInfoName,
|
||||
generateContactInfoBasic,
|
||||
isFriend,
|
||||
isApplicationType,
|
||||
} from '../utils/index';
|
||||
import {
|
||||
contactMoreInfoConfig,
|
||||
contactButtonConfig,
|
||||
} from './contact-info-config';
|
||||
import Icon from '../../common/Icon.vue';
|
||||
import editSVG from '../../../assets/icon/edit.svg';
|
||||
import backSVG from '../../../assets/icon/back.svg';
|
||||
import SwitchBar from '../../common/SwitchBar/index.vue';
|
||||
import {
|
||||
IBlackListUserItem,
|
||||
IContactInfoMoreItem,
|
||||
IContactInfoButton,
|
||||
} from '../../../interface';
|
||||
import {
|
||||
CONTACT_INFO_LABEL_POSITION,
|
||||
CONTACT_INFO_MORE_EDIT_TYPE,
|
||||
CONTACT_INFO_BUTTON_TYPE,
|
||||
} from '../../../constant';
|
||||
import { deepCopy } from '../../TUIChat/utils/utils';
|
||||
|
||||
type IContactInfoType = IGroupModel | Friend | FriendApplication | IBlackListUserItem;
|
||||
|
||||
const emits = defineEmits(['switchConversation']);
|
||||
|
||||
const contactInfoData = ref<IContactInfoType>({} as IContactInfoType);
|
||||
const contactInfoBasicList = ref<Array<{ label: string; data: string }>>([]);
|
||||
const contactInfoMoreList = ref<IContactInfoMoreItem[]>([]);
|
||||
const contactInfoButtonList = ref<IContactInfoButton[]>([]);
|
||||
|
||||
const setEditing = (item: any) => {
|
||||
item.editing = true;
|
||||
};
|
||||
|
||||
const isGroup = computed((): boolean =>
|
||||
(contactInfoData.value as IGroupModel)?.groupID ? true : false,
|
||||
);
|
||||
|
||||
const isApplication = computed((): boolean => {
|
||||
return isApplicationType(contactInfoData?.value);
|
||||
});
|
||||
|
||||
// is both friend, if is group type always false
|
||||
const isBothFriend = ref<boolean>(false);
|
||||
|
||||
// is group member, including ordinary member, admin, group owner
|
||||
const isGroupMember = computed((): boolean => {
|
||||
return (contactInfoData.value as IGroupModel)?.selfInfo?.userID ? true : false;
|
||||
});
|
||||
|
||||
// is in black list, if is group type always false
|
||||
const isInBlackList = computed((): boolean => {
|
||||
return (
|
||||
!isGroup.value
|
||||
&& blackList.value?.findIndex(
|
||||
(item: IBlackListUserItem) =>
|
||||
item?.userID === (contactInfoData.value as IBlackListUserItem)?.userID,
|
||||
) >= 0
|
||||
);
|
||||
});
|
||||
|
||||
const blackList = ref<IBlackListUserItem[]>([]);
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CUSTOM, {
|
||||
currentContactInfo: onCurrentContactInfoUpdated,
|
||||
});
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
userBlacklist: onUserBlacklistUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CUSTOM, {
|
||||
currentContactInfo: onCurrentContactInfoUpdated,
|
||||
});
|
||||
TUIStore.unwatch(StoreName.USER, {
|
||||
userBlacklist: onUserBlacklistUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
const resetContactInfoUIData = () => {
|
||||
contactInfoData.value = {} as IContactInfoType;
|
||||
contactInfoBasicList.value = [];
|
||||
contactInfoMoreList.value = [];
|
||||
contactInfoButtonList.value = [];
|
||||
};
|
||||
|
||||
const resetContactSearchingUIData = () => {
|
||||
TUIStore.update(StoreName.CUSTOM, 'currentContactInfo', {});
|
||||
TUIStore.update(StoreName.CUSTOM, 'currentContactSearchingStatus', false);
|
||||
TUIGlobal?.closeSearching && TUIGlobal?.closeSearching();
|
||||
};
|
||||
|
||||
const onContactInfoEmitSubmit = (item: any) => {
|
||||
item.editSubmitHandler
|
||||
&& item.editSubmitHandler({
|
||||
item,
|
||||
contactInfoData: contactInfoData.value,
|
||||
isBothFriend: isBothFriend.value,
|
||||
isInBlackList: isInBlackList.value,
|
||||
});
|
||||
};
|
||||
|
||||
const onContactInfoButtonClicked = (item: any) => {
|
||||
item.onClick
|
||||
&& item.onClick({
|
||||
contactInfoData: contactInfoData.value,
|
||||
contactInfoMoreList: contactInfoMoreList.value,
|
||||
});
|
||||
if (
|
||||
item.key === 'enterGroupConversation'
|
||||
|| item.key === 'enterC2CConversation'
|
||||
) {
|
||||
emits('switchConversation', contactInfoData.value);
|
||||
resetContactSearchingUIData();
|
||||
}
|
||||
};
|
||||
|
||||
const generateMoreInfo = async () => {
|
||||
if (!isApplication.value) {
|
||||
if (
|
||||
(!isGroup.value && !isBothFriend.value && !isInBlackList.value)
|
||||
|| (isGroup.value
|
||||
&& !isGroupMember.value
|
||||
&& (contactInfoData.value as IGroupModel)?.type !== TUIChatEngine?.TYPES?.GRP_AVCHATROOM)
|
||||
) {
|
||||
contactMoreInfoConfig.setWords.data = '';
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.setWords);
|
||||
}
|
||||
if (!isGroup.value && !isInBlackList.value) {
|
||||
contactMoreInfoConfig.setRemark.data
|
||||
= (contactInfoData.value as Friend)?.remark || '';
|
||||
contactMoreInfoConfig.setRemark.editing = false;
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.setRemark);
|
||||
}
|
||||
if (!isGroup.value && (isBothFriend.value || isInBlackList.value)) {
|
||||
contactMoreInfoConfig.blackList.data = isInBlackList.value || false;
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.blackList);
|
||||
}
|
||||
} else {
|
||||
contactMoreInfoConfig.displayWords.data
|
||||
= (contactInfoData.value as FriendApplication)?.wording || '';
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.displayWords);
|
||||
}
|
||||
};
|
||||
|
||||
const generateButton = () => {
|
||||
if (isInBlackList.value) {
|
||||
return;
|
||||
}
|
||||
if (isApplication.value) {
|
||||
if (
|
||||
(contactInfoData.value as FriendApplication)?.type
|
||||
=== TUIChatEngine?.TYPES?.SNS_APPLICATION_SENT_TO_ME
|
||||
) {
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.refuseFriendApplication,
|
||||
);
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.acceptFriendApplication,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (isGroup.value && isGroupMember.value) {
|
||||
switch ((contactInfoData.value as IGroupModel)?.selfInfo?.role) {
|
||||
case 'Owner':
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.dismissGroup);
|
||||
break;
|
||||
default:
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.quitGroup);
|
||||
break;
|
||||
}
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.enterGroupConversation,
|
||||
);
|
||||
} else if (!isGroup.value && isBothFriend.value) {
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.deleteFriend);
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.enterC2CConversation,
|
||||
);
|
||||
} else {
|
||||
if (isGroup.value) {
|
||||
contactInfoButtonList?.value?.push(
|
||||
(contactInfoData.value as IGroupModel)?.type === TUIChatEngine?.TYPES?.GRP_AVCHATROOM
|
||||
? contactButtonConfig.joinAVChatGroup
|
||||
: contactButtonConfig.joinGroup,
|
||||
);
|
||||
} else {
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.addFriend);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onUserBlacklistUpdated(userBlacklist: IBlackListUserItem[]) {
|
||||
blackList.value = userBlacklist;
|
||||
}
|
||||
|
||||
async function onCurrentContactInfoUpdated(contactInfo: IContactInfoType) {
|
||||
if (
|
||||
contactInfoData.value
|
||||
&& contactInfo
|
||||
&& JSON.stringify(contactInfoData.value) === JSON.stringify(contactInfo)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
resetContactInfoUIData();
|
||||
// deep clone
|
||||
contactInfoData.value = deepCopy(contactInfo) || {};
|
||||
if (!contactInfoData.value || Object.keys(contactInfoData.value)?.length === 0) {
|
||||
return;
|
||||
}
|
||||
contactInfoBasicList.value = generateContactInfoBasic(
|
||||
contactInfoData.value,
|
||||
);
|
||||
isBothFriend.value = await isFriend(contactInfoData.value);
|
||||
generateMoreInfo();
|
||||
generateButton();
|
||||
if (contactInfo.infoKeyList) {
|
||||
contactInfoMoreList.value = contactInfo.infoKeyList.map((key: string) => {
|
||||
return (contactMoreInfoConfig as any)[key];
|
||||
});
|
||||
}
|
||||
if (contactInfo.btnKeyList) {
|
||||
contactInfoButtonList.value = contactInfo.btnKeyList.map((key: string) => {
|
||||
return (contactButtonConfig as any)[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped src="./style/index.scss"></style>
|
||||
<template>
|
||||
<div
|
||||
:style="{height: '100%'}"
|
||||
v-if="typeof contactInfoData === 'object' && Object.keys(contactInfoData).length"
|
||||
:class="['tui-contact-info', !isPC && 'tui-contact-info-h5']"
|
||||
>
|
||||
<div
|
||||
v-if="!isPC"
|
||||
:class="[
|
||||
'tui-contact-info-header',
|
||||
!isPC && 'tui-contact-info-h5-header',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-header-icon',
|
||||
!isPC && 'tui-contact-info-h5-header-icon',
|
||||
]"
|
||||
@click="resetContactSearchingUIData"
|
||||
>
|
||||
<Icon :file="backSVG" />
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-header-title',
|
||||
!isPC && 'tui-contact-info-h5-header-title',
|
||||
]"
|
||||
>
|
||||
{{ TUITranslateService.t("TUIContact.添加好友/群聊") }}
|
||||
</div>
|
||||
</div>
|
||||
<div :class="['tui-contact-info-basic', !isPC && 'tui-contact-info-h5-basic']">
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-basic-text',
|
||||
!isPC && 'tui-contact-info-h5-basic-text',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-basic-text-name',
|
||||
!isPC && 'tui-contact-info-h5-basic-text-name',
|
||||
]"
|
||||
>
|
||||
{{ generateContactInfoName(contactInfoData) }}
|
||||
</div>
|
||||
<div
|
||||
v-for="item in contactInfoBasicList"
|
||||
:key="item.label"
|
||||
:class="[
|
||||
'tui-contact-info-basic-text-other',
|
||||
!isPC && 'tui-contact-info-h5-basic-text-other',
|
||||
]"
|
||||
>
|
||||
{{
|
||||
`${TUITranslateService.t(`TUIContact.${item.label}`)}:
|
||||
${item.data}`
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
:class="[
|
||||
'tui-contact-info-basic-avatar',
|
||||
!isPC && 'tui-contact-info-h5-basic-avatar',
|
||||
]"
|
||||
:src="generateAvatar(contactInfoData)"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
v-if="contactInfoMoreList[0]"
|
||||
:class="['tui-contact-info-more', !isPC && 'tui-contact-info-h5-more']"
|
||||
>
|
||||
<div
|
||||
v-for="item in contactInfoMoreList"
|
||||
:key="item.key"
|
||||
:class="[
|
||||
'tui-contact-info-more-item',
|
||||
!isPC && 'tui-contact-info-h5-more-item',
|
||||
item.labelPosition === CONTACT_INFO_LABEL_POSITION.TOP
|
||||
? 'tui-contact-info-more-item-top'
|
||||
: 'tui-contact-info-more-item-left',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-more-item-label',
|
||||
!isPC && 'tui-contact-info-h5-more-item-label',
|
||||
]"
|
||||
>
|
||||
{{ `${TUITranslateService.t(`TUIContact.${item.label}`)}` }}
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
v-if="!item.editing"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-text',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-text',
|
||||
]"
|
||||
>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-text-data',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-text-data',
|
||||
]"
|
||||
>
|
||||
{{ item.data }}
|
||||
</div>
|
||||
<div
|
||||
v-if="item.editable"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-text-icon',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-text-icon',
|
||||
]"
|
||||
@click="setEditing(item)"
|
||||
>
|
||||
<Icon
|
||||
:file="editSVG"
|
||||
width="14px"
|
||||
height="14px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.INPUT"
|
||||
v-model="item.data"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-input',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-input',
|
||||
]"
|
||||
type="text"
|
||||
@confirm="onContactInfoEmitSubmit(item)"
|
||||
@keyup.enter="onContactInfoEmitSubmit(item)"
|
||||
>
|
||||
<textarea
|
||||
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.TEXTAREA"
|
||||
v-model="item.data"
|
||||
:class="[
|
||||
'tui-contact-info-more-item-content-textarea',
|
||||
!isPC && 'tui-contact-info-h5-more-item-content-textarea',
|
||||
]"
|
||||
confirm-type="done"
|
||||
/>
|
||||
<div
|
||||
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.SWITCH"
|
||||
@click="onContactInfoEmitSubmit(item)"
|
||||
>
|
||||
<SwitchBar :value="item.data" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'tui-contact-info-button',
|
||||
!isPC && 'tui-contact-info-h5-button',
|
||||
]"
|
||||
>
|
||||
<button
|
||||
v-for="item in contactInfoButtonList"
|
||||
:key="item.key"
|
||||
:class="[
|
||||
'tui-contact-info-button-item',
|
||||
!isPC && 'tui-contact-info-h5-button-item',
|
||||
item.type === CONTACT_INFO_BUTTON_TYPE.CANCEL
|
||||
? `tui-contact-info-button-item-cancel`
|
||||
: `tui-contact-info-button-item-submit`,
|
||||
]"
|
||||
@click="onContactInfoButtonClicked(item)"
|
||||
>
|
||||
{{ TUITranslateService.t(`TUIContact.${item.label}`) }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import TUIChatEngine, {
|
||||
TUIStore,
|
||||
StoreName,
|
||||
TUITranslateService,
|
||||
IGroupModel,
|
||||
Friend,
|
||||
FriendApplication,
|
||||
} from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import { ref, computed, onMounted, onUnmounted } from '../../../adapter-vue';
|
||||
import { isPC } from '../../../utils/env';
|
||||
|
||||
import {
|
||||
generateAvatar,
|
||||
generateContactInfoName,
|
||||
generateContactInfoBasic,
|
||||
isFriend,
|
||||
isApplicationType,
|
||||
} from '../utils/index';
|
||||
import {
|
||||
contactMoreInfoConfig,
|
||||
contactButtonConfig,
|
||||
} from './contact-info-config';
|
||||
import Icon from '../../common/Icon.vue';
|
||||
import editSVG from '../../../assets/icon/edit.svg';
|
||||
import backSVG from '../../../assets/icon/back.svg';
|
||||
import SwitchBar from '../../common/SwitchBar/index.vue';
|
||||
import {
|
||||
IBlackListUserItem,
|
||||
IContactInfoMoreItem,
|
||||
IContactInfoButton,
|
||||
} from '../../../interface';
|
||||
import {
|
||||
CONTACT_INFO_LABEL_POSITION,
|
||||
CONTACT_INFO_MORE_EDIT_TYPE,
|
||||
CONTACT_INFO_BUTTON_TYPE,
|
||||
} from '../../../constant';
|
||||
import { deepCopy } from '../../TUIChat/utils/utils';
|
||||
|
||||
type IContactInfoType = IGroupModel | Friend | FriendApplication | IBlackListUserItem;
|
||||
|
||||
const emits = defineEmits(['switchConversation']);
|
||||
|
||||
const contactInfoData = ref<IContactInfoType>({} as IContactInfoType);
|
||||
const contactInfoBasicList = ref<Array<{ label: string; data: string }>>([]);
|
||||
const contactInfoMoreList = ref<IContactInfoMoreItem[]>([]);
|
||||
const contactInfoButtonList = ref<IContactInfoButton[]>([]);
|
||||
|
||||
const setEditing = (item: any) => {
|
||||
item.editing = true;
|
||||
};
|
||||
|
||||
const isGroup = computed((): boolean =>
|
||||
(contactInfoData.value as IGroupModel)?.groupID ? true : false,
|
||||
);
|
||||
|
||||
const isApplication = computed((): boolean => {
|
||||
return isApplicationType(contactInfoData?.value);
|
||||
});
|
||||
|
||||
// is both friend, if is group type always false
|
||||
const isBothFriend = ref<boolean>(false);
|
||||
|
||||
// is group member, including ordinary member, admin, group owner
|
||||
const isGroupMember = computed((): boolean => {
|
||||
return (contactInfoData.value as IGroupModel)?.selfInfo?.userID ? true : false;
|
||||
});
|
||||
|
||||
// is in black list, if is group type always false
|
||||
const isInBlackList = computed((): boolean => {
|
||||
return (
|
||||
!isGroup.value
|
||||
&& blackList.value?.findIndex(
|
||||
(item: IBlackListUserItem) =>
|
||||
item?.userID === (contactInfoData.value as IBlackListUserItem)?.userID,
|
||||
) >= 0
|
||||
);
|
||||
});
|
||||
|
||||
const blackList = ref<IBlackListUserItem[]>([]);
|
||||
|
||||
onMounted(() => {
|
||||
TUIStore.watch(StoreName.CUSTOM, {
|
||||
currentContactInfo: onCurrentContactInfoUpdated,
|
||||
});
|
||||
TUIStore.watch(StoreName.USER, {
|
||||
userBlacklist: onUserBlacklistUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
TUIStore.unwatch(StoreName.CUSTOM, {
|
||||
currentContactInfo: onCurrentContactInfoUpdated,
|
||||
});
|
||||
TUIStore.unwatch(StoreName.USER, {
|
||||
userBlacklist: onUserBlacklistUpdated,
|
||||
});
|
||||
});
|
||||
|
||||
const resetContactInfoUIData = () => {
|
||||
contactInfoData.value = {} as IContactInfoType;
|
||||
contactInfoBasicList.value = [];
|
||||
contactInfoMoreList.value = [];
|
||||
contactInfoButtonList.value = [];
|
||||
};
|
||||
|
||||
const resetContactSearchingUIData = () => {
|
||||
TUIStore.update(StoreName.CUSTOM, 'currentContactInfo', {});
|
||||
TUIStore.update(StoreName.CUSTOM, 'currentContactSearchingStatus', false);
|
||||
TUIGlobal?.closeSearching && TUIGlobal?.closeSearching();
|
||||
};
|
||||
|
||||
const onContactInfoEmitSubmit = (item: any) => {
|
||||
item.editSubmitHandler
|
||||
&& item.editSubmitHandler({
|
||||
item,
|
||||
contactInfoData: contactInfoData.value,
|
||||
isBothFriend: isBothFriend.value,
|
||||
isInBlackList: isInBlackList.value,
|
||||
});
|
||||
};
|
||||
|
||||
const onContactInfoButtonClicked = (item: any) => {
|
||||
item.onClick
|
||||
&& item.onClick({
|
||||
contactInfoData: contactInfoData.value,
|
||||
contactInfoMoreList: contactInfoMoreList.value,
|
||||
});
|
||||
if (
|
||||
item.key === 'enterGroupConversation'
|
||||
|| item.key === 'enterC2CConversation'
|
||||
) {
|
||||
emits('switchConversation', contactInfoData.value);
|
||||
resetContactSearchingUIData();
|
||||
}
|
||||
};
|
||||
|
||||
const generateMoreInfo = async () => {
|
||||
if (!isApplication.value) {
|
||||
if (
|
||||
(!isGroup.value && !isBothFriend.value && !isInBlackList.value)
|
||||
|| (isGroup.value
|
||||
&& !isGroupMember.value
|
||||
&& (contactInfoData.value as IGroupModel)?.type !== TUIChatEngine?.TYPES?.GRP_AVCHATROOM)
|
||||
) {
|
||||
contactMoreInfoConfig.setWords.data = '';
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.setWords);
|
||||
}
|
||||
if (!isGroup.value && !isInBlackList.value) {
|
||||
contactMoreInfoConfig.setRemark.data
|
||||
= (contactInfoData.value as Friend)?.remark || '';
|
||||
contactMoreInfoConfig.setRemark.editing = false;
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.setRemark);
|
||||
}
|
||||
if (!isGroup.value && (isBothFriend.value || isInBlackList.value)) {
|
||||
contactMoreInfoConfig.blackList.data = isInBlackList.value || false;
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.blackList);
|
||||
}
|
||||
} else {
|
||||
contactMoreInfoConfig.displayWords.data
|
||||
= (contactInfoData.value as FriendApplication)?.wording || '';
|
||||
contactInfoMoreList.value.push(contactMoreInfoConfig.displayWords);
|
||||
}
|
||||
};
|
||||
|
||||
const generateButton = () => {
|
||||
if (isInBlackList.value) {
|
||||
return;
|
||||
}
|
||||
if (isApplication.value) {
|
||||
if (
|
||||
(contactInfoData.value as FriendApplication)?.type
|
||||
=== TUIChatEngine?.TYPES?.SNS_APPLICATION_SENT_TO_ME
|
||||
) {
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.refuseFriendApplication,
|
||||
);
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.acceptFriendApplication,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (isGroup.value && isGroupMember.value) {
|
||||
switch ((contactInfoData.value as IGroupModel)?.selfInfo?.role) {
|
||||
case 'Owner':
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.dismissGroup);
|
||||
break;
|
||||
default:
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.quitGroup);
|
||||
break;
|
||||
}
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.enterGroupConversation,
|
||||
);
|
||||
} else if (!isGroup.value && isBothFriend.value) {
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.deleteFriend);
|
||||
contactInfoButtonList?.value?.push(
|
||||
contactButtonConfig.enterC2CConversation,
|
||||
);
|
||||
} else {
|
||||
if (isGroup.value) {
|
||||
contactInfoButtonList?.value?.push(
|
||||
(contactInfoData.value as IGroupModel)?.type === TUIChatEngine?.TYPES?.GRP_AVCHATROOM
|
||||
? contactButtonConfig.joinAVChatGroup
|
||||
: contactButtonConfig.joinGroup,
|
||||
);
|
||||
} else {
|
||||
contactInfoButtonList?.value?.push(contactButtonConfig.addFriend);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function onUserBlacklistUpdated(userBlacklist: IBlackListUserItem[]) {
|
||||
blackList.value = userBlacklist;
|
||||
}
|
||||
|
||||
async function onCurrentContactInfoUpdated(contactInfo: IContactInfoType) {
|
||||
if (
|
||||
contactInfoData.value
|
||||
&& contactInfo
|
||||
&& JSON.stringify(contactInfoData.value) === JSON.stringify(contactInfo)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
resetContactInfoUIData();
|
||||
// deep clone
|
||||
contactInfoData.value = deepCopy(contactInfo) || {};
|
||||
if (!contactInfoData.value || Object.keys(contactInfoData.value)?.length === 0) {
|
||||
return;
|
||||
}
|
||||
contactInfoBasicList.value = generateContactInfoBasic(
|
||||
contactInfoData.value,
|
||||
);
|
||||
isBothFriend.value = await isFriend(contactInfoData.value);
|
||||
generateMoreInfo();
|
||||
generateButton();
|
||||
if (contactInfo.infoKeyList) {
|
||||
contactInfoMoreList.value = contactInfo.infoKeyList.map((key: string) => {
|
||||
return (contactMoreInfoConfig as any)[key];
|
||||
});
|
||||
}
|
||||
if (contactInfo.btnKeyList) {
|
||||
contactInfoButtonList.value = contactInfo.btnKeyList.map((key: string) => {
|
||||
return (contactButtonConfig as any)[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped src="./style/index.scss"></style>
|
||||
|
||||
@ -1,138 +1,138 @@
|
||||
<template>
|
||||
<SelectFriend v-if="isShowSelectFriend" />
|
||||
<div
|
||||
v-else-if="isShowContactList"
|
||||
:class="['tui-contact', !isPC && 'tui-contact-h5']"
|
||||
>
|
||||
<div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}">
|
||||
<!-- <ContactSearch /> -->
|
||||
<ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" />
|
||||
</div>
|
||||
<div
|
||||
v-if="isShowContactInfo"
|
||||
:class="['tui-contact-right', !isPC && 'tui-contact-h5-right']"
|
||||
:style="{height:ht+'px'}"
|
||||
>
|
||||
<ContactInfo @switchConversation="switchConversation" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import { ref, watchEffect,defineProps } from '../../adapter-vue';
|
||||
import { isPC, isUniFrameWork } from '../../utils/env';
|
||||
const ht = uni.getSystemInfoSync().windowHeight
|
||||
import SelectFriend from './select-friend/index.vue';
|
||||
import ContactSearch from './contact-search/index.vue';
|
||||
import ContactList from './contact-list/index.vue';
|
||||
import ContactInfo from './contact-info/index.vue';
|
||||
|
||||
const emits = defineEmits(['switchConversation']);
|
||||
|
||||
const props = defineProps({
|
||||
// web/h5 single page application display format, uniapp please ignore
|
||||
displayType: {
|
||||
type: String,
|
||||
default: 'contactList', // "contactList" / "selectFriend"
|
||||
require: false,
|
||||
|
||||
},
|
||||
stu: {
|
||||
type: Number, // 这里可以根据实际类型修改,如 String, Number, Object 等
|
||||
require: true,
|
||||
}
|
||||
});
|
||||
|
||||
const displayTypeRef = ref<string>(props.displayType || 'contactList');
|
||||
const isShowSelectFriend = ref(false);
|
||||
const isShowContactList = ref(true);
|
||||
const isShowContactInfo = ref(true);
|
||||
const isstu=ref(props.stu);
|
||||
|
||||
watchEffect(() => {
|
||||
isShowContactList.value = props?.displayType !== 'selectFriend';
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CUSTOM, {
|
||||
isShowSelectFriendComponent: (data: any) => {
|
||||
if (!isUniFrameWork && props?.displayType === 'selectFriend') {
|
||||
isShowSelectFriend.value = data;
|
||||
isShowContactList.value = false;
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
isShowSelectFriend.value = true;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = 'selectFriend';
|
||||
TUIGlobal?.hideTabBar();
|
||||
}
|
||||
} else {
|
||||
isShowSelectFriend.value = false;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = props.displayType;
|
||||
TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ });
|
||||
}
|
||||
}
|
||||
},
|
||||
currentContactInfo: (contactInfo: any) => {
|
||||
isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0);
|
||||
},
|
||||
});
|
||||
|
||||
const switchConversation = (data: any) => {
|
||||
isUniFrameWork
|
||||
&& TUIGlobal?.navigateTo({
|
||||
url: '/TUIKit/components/TUIChat/index',
|
||||
});
|
||||
emits('switchConversation', data);
|
||||
};
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../../assets/styles/common";
|
||||
|
||||
.tui-contact {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&-left {
|
||||
min-width: 285px;
|
||||
flex: 0 0 24%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-right {
|
||||
border-left: 1px solid #f4f5f9;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.tui-contact-h5 {
|
||||
position: relative;
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&-right {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
&-left {
|
||||
&-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<SelectFriend v-if="isShowSelectFriend" />
|
||||
<div
|
||||
v-else-if="isShowContactList"
|
||||
:class="['tui-contact', !isPC && 'tui-contact-h5']"
|
||||
>
|
||||
<div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}">
|
||||
<!-- <ContactSearch /> -->
|
||||
<ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" />
|
||||
</div>
|
||||
<div
|
||||
v-if="isShowContactInfo"
|
||||
:class="['tui-contact-right', !isPC && 'tui-contact-h5-right']"
|
||||
:style="{height:ht+'px'}"
|
||||
>
|
||||
<ContactInfo @switchConversation="switchConversation" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import { ref, watchEffect,defineProps } from '../../adapter-vue';
|
||||
import { isPC, isUniFrameWork } from '../../utils/env';
|
||||
const ht = uni.getSystemInfoSync().windowHeight
|
||||
import SelectFriend from './select-friend/index.vue';
|
||||
import ContactSearch from './contact-search/index.vue';
|
||||
import ContactList from './contact-list/index.vue';
|
||||
import ContactInfo from './contact-info/index.vue';
|
||||
|
||||
const emits = defineEmits(['switchConversation']);
|
||||
|
||||
const props = defineProps({
|
||||
// web/h5 single page application display format, uniapp please ignore
|
||||
displayType: {
|
||||
type: String,
|
||||
default: 'contactList', // "contactList" / "selectFriend"
|
||||
require: false,
|
||||
|
||||
},
|
||||
stu: {
|
||||
type: Number, // 这里可以根据实际类型修改,如 String, Number, Object 等
|
||||
require: true,
|
||||
}
|
||||
});
|
||||
|
||||
const displayTypeRef = ref<string>(props.displayType || 'contactList');
|
||||
const isShowSelectFriend = ref(false);
|
||||
const isShowContactList = ref(true);
|
||||
const isShowContactInfo = ref(true);
|
||||
const isstu=ref(props.stu);
|
||||
|
||||
watchEffect(() => {
|
||||
isShowContactList.value = props?.displayType !== 'selectFriend';
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CUSTOM, {
|
||||
isShowSelectFriendComponent: (data: any) => {
|
||||
if (!isUniFrameWork && props?.displayType === 'selectFriend') {
|
||||
isShowSelectFriend.value = data;
|
||||
isShowContactList.value = false;
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
isShowSelectFriend.value = true;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = 'selectFriend';
|
||||
TUIGlobal?.hideTabBar();
|
||||
}
|
||||
} else {
|
||||
isShowSelectFriend.value = false;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = props.displayType;
|
||||
TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ });
|
||||
}
|
||||
}
|
||||
},
|
||||
currentContactInfo: (contactInfo: any) => {
|
||||
isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0);
|
||||
},
|
||||
});
|
||||
|
||||
const switchConversation = (data: any) => {
|
||||
isUniFrameWork
|
||||
&& TUIGlobal?.navigateTo({
|
||||
url: '/TUIKit/components/TUIChat/index',
|
||||
});
|
||||
emits('switchConversation', data);
|
||||
};
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../../assets/styles/common";
|
||||
|
||||
.tui-contact {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&-left {
|
||||
min-width: 285px;
|
||||
flex: 0 0 24%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-right {
|
||||
border-left: 1px solid #f4f5f9;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.tui-contact-h5 {
|
||||
position: relative;
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&-right {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
&-left {
|
||||
&-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,141 +1,141 @@
|
||||
<template>
|
||||
<SelectFriend v-if="isShowSelectFriend" />
|
||||
<div
|
||||
v-else-if="isShowContactList"
|
||||
:class="['tui-contact', !isPC && 'tui-contact-h5']"
|
||||
>
|
||||
<div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}" >
|
||||
<ContactSearch @cancel="cancel" />
|
||||
<ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" />
|
||||
</div>
|
||||
<div
|
||||
v-if="isShowContactInfo"
|
||||
:class="['tui-contact-right', !isPC && 'tui-contact-h5-right']"
|
||||
:style="{height:ht+'px'}"
|
||||
>
|
||||
<ContactInfo @switchConversation="switchConversation" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import { ref, watchEffect,defineProps } from '../../adapter-vue';
|
||||
import { isPC, isUniFrameWork } from '../../utils/env';
|
||||
|
||||
import SelectFriend from './select-friend/index.vue';
|
||||
import ContactSearch from './contact-search/index.vue';
|
||||
import ContactList from './contact-list/indexsea.vue';
|
||||
import ContactInfo from './contact-info/index.vue';
|
||||
|
||||
const emits = defineEmits(['switchConversation']);
|
||||
const ht = uni.getSystemInfoSync().windowHeight
|
||||
const props = defineProps({
|
||||
// web/h5 single page application display format, uniapp please ignore
|
||||
displayType: {
|
||||
type: String,
|
||||
default: 'contactList', // "contactList" / "selectFriend"
|
||||
require: false,
|
||||
|
||||
},
|
||||
stu: {
|
||||
type: Number, // 这里可以根据实际类型修改,如 String, Number, Object 等
|
||||
require: true,
|
||||
}
|
||||
});
|
||||
const cancel=(item)=>{
|
||||
emits('switchConversation', item);
|
||||
}
|
||||
const displayTypeRef = ref<string>(props.displayType || 'contactList');
|
||||
const isShowSelectFriend = ref(false);
|
||||
const isShowContactList = ref(true);
|
||||
const isShowContactInfo = ref(true);
|
||||
const isstu=ref(props.stu);
|
||||
|
||||
watchEffect(() => {
|
||||
isShowContactList.value = props?.displayType !== 'selectFriend';
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CUSTOM, {
|
||||
isShowSelectFriendComponent: (data: any) => {
|
||||
if (!isUniFrameWork && props?.displayType === 'selectFriend') {
|
||||
isShowSelectFriend.value = data;
|
||||
isShowContactList.value = false;
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
isShowSelectFriend.value = true;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = 'selectFriend';
|
||||
TUIGlobal?.hideTabBar();
|
||||
}
|
||||
} else {
|
||||
isShowSelectFriend.value = false;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = props.displayType;
|
||||
TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ });
|
||||
}
|
||||
}
|
||||
},
|
||||
currentContactInfo: (contactInfo: any) => {
|
||||
isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0);
|
||||
},
|
||||
});
|
||||
|
||||
const switchConversation = (data: any) => {
|
||||
isUniFrameWork
|
||||
&& TUIGlobal?.navigateTo({
|
||||
url: '/TUIKit/components/TUIChat/index',
|
||||
});
|
||||
emits('switchConversation', data);
|
||||
};
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../../assets/styles/common";
|
||||
|
||||
.tui-contact {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&-left {
|
||||
min-width: 285px;
|
||||
flex: 0 0 24%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-right {
|
||||
border-left: 1px solid #f4f5f9;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.tui-contact-h5 {
|
||||
position: relative;
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&-right {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
&-left {
|
||||
&-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<SelectFriend v-if="isShowSelectFriend" />
|
||||
<div
|
||||
v-else-if="isShowContactList"
|
||||
:class="['tui-contact', !isPC && 'tui-contact-h5']"
|
||||
>
|
||||
<div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}" >
|
||||
<ContactSearch @cancel="cancel" />
|
||||
<ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" />
|
||||
</div>
|
||||
<div
|
||||
v-if="isShowContactInfo"
|
||||
:class="['tui-contact-right', !isPC && 'tui-contact-h5-right']"
|
||||
:style="{height:ht+'px'}"
|
||||
>
|
||||
<ContactInfo @switchConversation="switchConversation" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
|
||||
import { TUIGlobal } from '@tencentcloud/universal-api';
|
||||
import { ref, watchEffect,defineProps } from '../../adapter-vue';
|
||||
import { isPC, isUniFrameWork } from '../../utils/env';
|
||||
|
||||
import SelectFriend from './select-friend/index.vue';
|
||||
import ContactSearch from './contact-search/index.vue';
|
||||
import ContactList from './contact-list/indexsea.vue';
|
||||
import ContactInfo from './contact-info/index.vue';
|
||||
|
||||
const emits = defineEmits(['switchConversation']);
|
||||
const ht = uni.getSystemInfoSync().windowHeight
|
||||
const props = defineProps({
|
||||
// web/h5 single page application display format, uniapp please ignore
|
||||
displayType: {
|
||||
type: String,
|
||||
default: 'contactList', // "contactList" / "selectFriend"
|
||||
require: false,
|
||||
|
||||
},
|
||||
stu: {
|
||||
type: Number, // 这里可以根据实际类型修改,如 String, Number, Object 等
|
||||
require: true,
|
||||
}
|
||||
});
|
||||
const cancel=(item)=>{
|
||||
emits('switchConversation', item);
|
||||
}
|
||||
const displayTypeRef = ref<string>(props.displayType || 'contactList');
|
||||
const isShowSelectFriend = ref(false);
|
||||
const isShowContactList = ref(true);
|
||||
const isShowContactInfo = ref(true);
|
||||
const isstu=ref(props.stu);
|
||||
|
||||
watchEffect(() => {
|
||||
isShowContactList.value = props?.displayType !== 'selectFriend';
|
||||
});
|
||||
|
||||
TUIStore.watch(StoreName.CUSTOM, {
|
||||
isShowSelectFriendComponent: (data: any) => {
|
||||
if (!isUniFrameWork && props?.displayType === 'selectFriend') {
|
||||
isShowSelectFriend.value = data;
|
||||
isShowContactList.value = false;
|
||||
return;
|
||||
}
|
||||
if (data) {
|
||||
isShowSelectFriend.value = true;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = 'selectFriend';
|
||||
TUIGlobal?.hideTabBar();
|
||||
}
|
||||
} else {
|
||||
isShowSelectFriend.value = false;
|
||||
if (isUniFrameWork) {
|
||||
displayTypeRef.value = props.displayType;
|
||||
TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ });
|
||||
}
|
||||
}
|
||||
},
|
||||
currentContactInfo: (contactInfo: any) => {
|
||||
isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0);
|
||||
},
|
||||
});
|
||||
|
||||
const switchConversation = (data: any) => {
|
||||
isUniFrameWork
|
||||
&& TUIGlobal?.navigateTo({
|
||||
url: '/TUIKit/components/TUIChat/index',
|
||||
});
|
||||
emits('switchConversation', data);
|
||||
};
|
||||
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import "../../assets/styles/common";
|
||||
|
||||
.tui-contact {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
|
||||
&-left {
|
||||
min-width: 285px;
|
||||
flex: 0 0 24%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
&-right {
|
||||
border-left: 1px solid #f4f5f9;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.tui-contact-h5 {
|
||||
position: relative;
|
||||
|
||||
&-left,
|
||||
&-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&-right {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
&-left {
|
||||
&-list {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
828
api/vlog.js
828
api/vlog.js
@ -1,353 +1,477 @@
|
||||
/**
|
||||
* 短视频相关API
|
||||
*/
|
||||
|
||||
import { http, Method } from "@/utils/request.js";
|
||||
|
||||
import api from "@/config/api.js";
|
||||
|
||||
|
||||
/**
|
||||
* 短视频关注列表
|
||||
*/
|
||||
export function vlogDetail(vlogId,userId) {
|
||||
let data = {
|
||||
vlogId,
|
||||
userId
|
||||
}
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/detail",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频关注列表
|
||||
*/
|
||||
export function vlogFollowList(page, pageSize,myId) {
|
||||
let data = {
|
||||
page,
|
||||
pageSize,
|
||||
myId
|
||||
}
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/followList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频列表-true
|
||||
*/
|
||||
export function vlogList(page, pageSize,userId='',cityCode='',search='') {
|
||||
let data = {
|
||||
page,
|
||||
pageSize,
|
||||
userId,
|
||||
cityCode,
|
||||
search
|
||||
}
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/indexList",
|
||||
method: Method.GET,
|
||||
needToken: false,
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频喜欢
|
||||
*/
|
||||
export function vlogLike({userId,vlogId,vlogerId}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/like",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {userId,vlogId,vlogerId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频不喜欢
|
||||
*/
|
||||
export function vlogUnLike({userId,vlogId,vlogerId}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/unlike",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {userId,vlogId,vlogerId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频评论数量统计
|
||||
*/
|
||||
export function vlogComment(vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/counts",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { vlogId },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 短视频关注博主
|
||||
*/
|
||||
export function vlogFollow(myId,vlogerId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/follow",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {myId,vlogerId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频查询当前点赞数
|
||||
*/
|
||||
export function vlogTotalLikedCounts(vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/totalLikedCounts",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {vlogId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户信息
|
||||
*/
|
||||
export function vlogUserInfo(userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/userInfo/query",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { userId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的公开视频
|
||||
*/
|
||||
export function vlogMyPublicList(page,pageSize,userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/myPublicList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { page,pageSize,userId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的私密视频
|
||||
*/
|
||||
export function vlogMyPrivateList(page,pageSize,userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/myPrivateList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { page,pageSize,userId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我喜欢的视频
|
||||
*/
|
||||
export function vlogMyLikedList(page,pageSize,userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/myLikedList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { page,pageSize,userId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我喜欢的视频
|
||||
*/
|
||||
export function vlogMeTag(path,page,pageSize,userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/"+path,
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { page,pageSize,userId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论数量
|
||||
*/
|
||||
export function vlogCommentCounts(vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/counts",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { vlogId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论不喜欢
|
||||
*/
|
||||
export function vlogCommentUnLike(userId,commentId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/unlike",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {userId,commentId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论喜欢
|
||||
*/
|
||||
export function vlogCommentLike(userId,commentId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/like",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {userId,commentId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论删除
|
||||
*/
|
||||
export function vlogCommentDelete(vlogId,commentUserId,commentId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/delete",
|
||||
method: Method.DELETE,
|
||||
needToken: true,
|
||||
params: {vlogId,commentUserId,commentId}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询视频评论内容
|
||||
*/
|
||||
export function vlogCommentList(page,pageSize,vlogId,userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/list",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: { page,pageSize,vlogId,userId },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发表评论
|
||||
*/
|
||||
export function vlogCommentCreate(data) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/create",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将视频转为公开
|
||||
*/
|
||||
export function vlogChangeToPublic(userId,vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/changeToPublic",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params:{userId,vlogId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将视频转为私密
|
||||
*/
|
||||
export function vlogChangeToPrivate(userId,vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/changeToPrivate",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params:{userId,vlogId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改信息
|
||||
*/
|
||||
export function vlogModifyUserInfo(data,type) {
|
||||
return http.request({
|
||||
url: api.vlog + "/userInfo/modifyUserInfo?type="+type,
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取关
|
||||
*/
|
||||
export function vlogFansCancel({myId,vlogerId}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/cancel",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params:{myId,vlogerId}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 关注
|
||||
*/
|
||||
export function vlogFansFollow({myId,vlogerId}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/follow",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params:{myId,vlogerId}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的粉丝
|
||||
*/
|
||||
export function vlogQueryMyFans({myId,page,pageSize}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/queryMyFans",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params:{myId,page,pageSize}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的关注
|
||||
*/
|
||||
export function vlogQueryMyFollows({myId,page,pageSize}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/queryMyFollows",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params:{myId,page,pageSize}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的关注
|
||||
*/
|
||||
export function vlogQueryDoIFollowVloger({myId,vlogerId}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/queryDoIFollowVloger",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params:{myId,vlogerId}
|
||||
});
|
||||
/**
|
||||
* 短视频相关API
|
||||
*/
|
||||
|
||||
import {
|
||||
http,
|
||||
Method
|
||||
} from "@/utils/request.js";
|
||||
|
||||
import api from "@/config/api.js";
|
||||
|
||||
|
||||
/**
|
||||
* 根据昵称搜索用户
|
||||
*/
|
||||
export function vlogSearchUser({
|
||||
id,
|
||||
nickname,
|
||||
page,
|
||||
pageSize
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/userInfo/searchByNickname",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
id,
|
||||
nickname,
|
||||
page,
|
||||
pageSize
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 短视频详情
|
||||
*/
|
||||
export function vlogDetail(vlogId, userId) {
|
||||
let data = {
|
||||
vlogId,
|
||||
userId
|
||||
}
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/detail",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频关注列表
|
||||
*/
|
||||
export function vlogFollowList(page, pageSize, myId) {
|
||||
let data = {
|
||||
page,
|
||||
pageSize,
|
||||
myId
|
||||
}
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/followList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频列表-true
|
||||
*/
|
||||
export function vlogList(page, pageSize, userId = '', cityCode = '', search = '') {
|
||||
let data = {
|
||||
page,
|
||||
pageSize,
|
||||
userId,
|
||||
cityCode,
|
||||
search
|
||||
}
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/indexList",
|
||||
method: Method.GET,
|
||||
needToken: false,
|
||||
params: data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频喜欢
|
||||
*/
|
||||
export function vlogLike({
|
||||
userId,
|
||||
vlogId,
|
||||
vlogerId
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/like",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId,
|
||||
vlogId,
|
||||
vlogerId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频不喜欢
|
||||
*/
|
||||
export function vlogUnLike({
|
||||
userId,
|
||||
vlogId,
|
||||
vlogerId
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/unlike",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId,
|
||||
vlogId,
|
||||
vlogerId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频评论数量统计
|
||||
*/
|
||||
export function vlogComment(vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/counts",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
vlogId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 短视频关注博主
|
||||
*/
|
||||
export function vlogFollow(myId, vlogerId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/follow",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
myId,
|
||||
vlogerId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 短视频查询当前点赞数
|
||||
*/
|
||||
export function vlogTotalLikedCounts(vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/totalLikedCounts",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
vlogId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户信息
|
||||
*/
|
||||
export function vlogUserInfo(userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/userInfo/query",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的公开视频
|
||||
*/
|
||||
export function vlogMyPublicList(page, pageSize, userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/myPublicList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
page,
|
||||
pageSize,
|
||||
userId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我的私密视频
|
||||
*/
|
||||
export function vlogMyPrivateList(page, pageSize, userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/myPrivateList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
page,
|
||||
pageSize,
|
||||
userId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我喜欢的视频
|
||||
*/
|
||||
export function vlogMyLikedList(page, pageSize, userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/myLikedList",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
page,
|
||||
pageSize,
|
||||
userId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询我喜欢的视频
|
||||
*/
|
||||
export function vlogMeTag(path, page, pageSize, userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/" + path,
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
page,
|
||||
pageSize,
|
||||
userId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论数量
|
||||
*/
|
||||
export function vlogCommentCounts(vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/counts",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
vlogId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论不喜欢
|
||||
*/
|
||||
export function vlogCommentUnLike(userId, commentId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/unlike",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId,
|
||||
commentId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论喜欢
|
||||
*/
|
||||
export function vlogCommentLike(userId, commentId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/like",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId,
|
||||
commentId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频评论删除
|
||||
*/
|
||||
export function vlogCommentDelete(vlogId, commentUserId, commentId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/delete",
|
||||
method: Method.DELETE,
|
||||
needToken: true,
|
||||
params: {
|
||||
vlogId,
|
||||
commentUserId,
|
||||
commentId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询视频评论内容
|
||||
*/
|
||||
export function vlogCommentList(page, pageSize, vlogId, userId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/list",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
page,
|
||||
pageSize,
|
||||
vlogId,
|
||||
userId
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 发表评论
|
||||
*/
|
||||
export function vlogCommentCreate(data) {
|
||||
return http.request({
|
||||
url: api.vlog + "/comment/create",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将视频转为公开
|
||||
*/
|
||||
export function vlogChangeToPublic(userId, vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/changeToPublic",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId,
|
||||
vlogId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将视频转为私密
|
||||
*/
|
||||
export function vlogChangeToPrivate(userId, vlogId) {
|
||||
return http.request({
|
||||
url: api.vlog + "/vlog/changeToPrivate",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
userId,
|
||||
vlogId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改信息
|
||||
*/
|
||||
export function vlogModifyUserInfo(data, type) {
|
||||
return http.request({
|
||||
url: api.vlog + "/userInfo/modifyUserInfo?type=" + type,
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取关
|
||||
*/
|
||||
export function vlogFansCancel({
|
||||
myId,
|
||||
vlogerId
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/cancel",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
myId,
|
||||
vlogerId
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 关注
|
||||
*/
|
||||
export function vlogFansFollow({
|
||||
myId,
|
||||
vlogerId
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/follow",
|
||||
method: Method.POST,
|
||||
needToken: true,
|
||||
params: {
|
||||
myId,
|
||||
vlogerId
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的粉丝
|
||||
*/
|
||||
export function vlogQueryMyFans({
|
||||
myId,
|
||||
page,
|
||||
pageSize
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/queryMyFans",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
myId,
|
||||
page,
|
||||
pageSize
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的关注
|
||||
*/
|
||||
export function vlogQueryMyFollows({
|
||||
myId,
|
||||
page,
|
||||
pageSize
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/queryMyFollows",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
myId,
|
||||
page,
|
||||
pageSize
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 我的关注
|
||||
*/
|
||||
export function vlogQueryDoIFollowVloger({
|
||||
myId,
|
||||
vlogerId
|
||||
}) {
|
||||
return http.request({
|
||||
url: api.vlog + "/fans/queryDoIFollowVloger",
|
||||
method: Method.GET,
|
||||
needToken: true,
|
||||
params: {
|
||||
myId,
|
||||
vlogerId
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -112,7 +112,8 @@
|
||||
<text class="muisc-words">{{ item.vlogerName }}的原声创作</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
<!-- 右下角 -->
|
||||
<!-- <view
|
||||
class=""
|
||||
style="flex-direction: row"
|
||||
>
|
||||
@ -120,17 +121,7 @@
|
||||
src="/static/images/cd-play-4.gif"
|
||||
style="width: 150rpx; height: 150rpx; opacity: 0.8"
|
||||
></image>
|
||||
<image
|
||||
v-if="!isIOS"
|
||||
src="/static/images/icon-cd.png"
|
||||
class="play-cd"
|
||||
></image>
|
||||
<image
|
||||
v-if="isIOS"
|
||||
:src="'https://imooc-news.oss-cn-shanghai.aliyuncs.com/image/cd-play-4.gif?time=' + times"
|
||||
class="play-cd"
|
||||
></image>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 视频展示右侧的操作按钮,头像 - 点赞 - 评论 - 转发 -->
|
||||
<view class="operation-box">
|
||||
@ -323,7 +314,6 @@ export default {
|
||||
|
||||
playStatus(val) {
|
||||
var me = this;
|
||||
console.log(val);
|
||||
if (!val) {
|
||||
me.videoContext.pause();
|
||||
} else {
|
||||
@ -839,7 +829,6 @@ export default {
|
||||
height: 2px;
|
||||
background-color: #ccc;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.progress-foreground {
|
||||
@ -849,7 +838,6 @@ export default {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.anm {
|
||||
transition: width 0.25s linear;
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
@click="playOrPause"
|
||||
@play="onplay"
|
||||
@error="onerror"
|
||||
@timeupdate="timeupdate"
|
||||
@timeupdate="onTimeUpdate"
|
||||
></video>
|
||||
<image
|
||||
:lazy-load="true"
|
||||
@ -75,7 +75,7 @@
|
||||
v-if="isDragging"
|
||||
:style="{ left: floatLeft + 'px' }"
|
||||
>
|
||||
{{ formatTime(floatTime) }}
|
||||
<text style="color: #fff">{{ formatTime(floatTime) }}</text>
|
||||
</view>
|
||||
|
||||
<view class="publish-info-box">
|
||||
@ -90,7 +90,7 @@
|
||||
<text class="muisc-words">{{ item.vlogerName }}的原声创作</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
<!-- <view
|
||||
class=""
|
||||
style="flex-direction: row"
|
||||
>
|
||||
@ -98,18 +98,7 @@
|
||||
src="/static/images/cd-play-4.gif"
|
||||
style="width: 150rpx; height: 150rpx; opacity: 0.8"
|
||||
></image>
|
||||
<image
|
||||
v-if="!isIOS"
|
||||
src="/static/images/icon-cd.png"
|
||||
class="play-cd"
|
||||
style="width: 120rpx; height: 120rpx"
|
||||
></image>
|
||||
<image
|
||||
v-if="isIOS"
|
||||
:src="'https://imooc-news.oss-cn-shanghai.aliyuncs.com/image/cd-play-4.gif?time=' + times"
|
||||
class="play-cd"
|
||||
></image>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 视频展示右侧的操作按钮, 头像 - 点赞 - 评论 - 转发 -->
|
||||
<view class="operation-box">
|
||||
@ -659,7 +648,6 @@ export default {
|
||||
height: 2px;
|
||||
background-color: #ccc;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.progress-foreground {
|
||||
@ -669,15 +657,14 @@ export default {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.anm {
|
||||
transition: width 0.25s linear;
|
||||
}
|
||||
|
||||
.float-time {
|
||||
position: absolute;
|
||||
bottom: 56px;
|
||||
position: fixed;
|
||||
bottom: 2px;
|
||||
width: 60px;
|
||||
height: 30px;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
@ -688,7 +675,7 @@ export default {
|
||||
line-height: 30px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
z-index: 1;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
.abs-box {
|
||||
@ -702,7 +689,6 @@ export default {
|
||||
position: absolute;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
pointer-events: none;
|
||||
}
|
||||
.icon {
|
||||
width: 80rpx;
|
||||
@ -728,7 +714,7 @@ export default {
|
||||
}
|
||||
.publish-info-box {
|
||||
position: absolute;
|
||||
bottom: 200rpx;
|
||||
bottom: 120rpx;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-left: 20rpx;
|
||||
|
||||
@ -122,24 +122,13 @@
|
||||
<text class="muisc-words">{{ item.vlogerName }}的原声创作</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
<!-- <view
|
||||
class=""
|
||||
style="flex-direction: row"
|
||||
>
|
||||
<!-- <image src="/static/images/cd-play-4.gif"
|
||||
style="width: 150rpx;height: 150rpx;opacity: 0.8;"></image> -->
|
||||
<image
|
||||
v-if="!isIOS"
|
||||
src="/static/images/icon-cd.png"
|
||||
class="play-cd"
|
||||
style="width: 120rpx; height: 120rpx"
|
||||
></image>
|
||||
<image
|
||||
v-if="isIOS"
|
||||
:src="'https://imooc-news.oss-cn-shanghai.aliyuncs.com/image/cd-play-4.gif?time=' + times"
|
||||
class="play-cd"
|
||||
></image>
|
||||
</view>
|
||||
<image src="/static/images/cd-play-4.gif"
|
||||
style="width: 150rpx;height: 150rpx;opacity: 0.8;"></image>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 视频展示右侧的操作按钮,头像 - 点赞 - 评论 - 转发 -->
|
||||
<view class="operation-box">
|
||||
@ -334,7 +323,6 @@ export default {
|
||||
},
|
||||
onTimeUpdate(e) {
|
||||
console.log(e.detail.currentTime);
|
||||
console.log(this.progressFlag);
|
||||
if (e.detail.currentTime > 0.2) {
|
||||
this.doplay(e.detail.currentTime);
|
||||
}
|
||||
@ -346,7 +334,6 @@ export default {
|
||||
updateProgress() {
|
||||
const percent = this.currentTime / this.duration;
|
||||
this.progressWidth = Math.floor(system.screenWidth * percent);
|
||||
console.log(this.progressWidth);
|
||||
},
|
||||
startDrag(e) {
|
||||
console.log('触发开始拖动');
|
||||
@ -690,6 +677,7 @@ export default {
|
||||
} else {
|
||||
// return;
|
||||
}
|
||||
console.log(myUserInfo);
|
||||
var result = await vlogFollowList(page, 10, userId);
|
||||
console.log(result);
|
||||
if (result.data.status == 200) {
|
||||
|
||||
@ -121,7 +121,7 @@
|
||||
<text class="muisc-words">{{ item.vlogerName }}的原声创作</text>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
<!-- <view
|
||||
class=""
|
||||
style="flex-direction: row"
|
||||
>
|
||||
@ -129,17 +129,7 @@
|
||||
src="/static/images/cd-play-4.gif"
|
||||
style="width: 150rpx; height: 150rpx; opacity: 0.8"
|
||||
></image>
|
||||
<image
|
||||
v-if="!isIOS"
|
||||
src="/static/images/icon-cd.png"
|
||||
class="play-cd"
|
||||
></image>
|
||||
<image
|
||||
v-if="isIOS"
|
||||
:src="'https://imooc-news.oss-cn-shanghai.aliyuncs.com/image/cd-play-4.gif?time=' + times"
|
||||
class="play-cd"
|
||||
></image>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
<!-- 视频展示右侧的操作按钮,头像 - 点赞 - 评论 - 转发 -->
|
||||
<view class="operation-box">
|
||||
|
||||
@ -7,19 +7,19 @@ const dev = {
|
||||
// common: "https://common-api.pickmall.cn",
|
||||
// buyer: "https://buyer-api.pickmall.cn",
|
||||
|
||||
common: "http://192.168.1.200:8890",
|
||||
buyer: "http://192.168.1.200:8888",
|
||||
vlog: "http://192.168.1.200:8099",
|
||||
web: "http://192.168.1.200:8099",
|
||||
common: "http://192.168.1.113:8890",
|
||||
buyer: "http://192.168.1.113:8888",
|
||||
vlog: "http://192.168.1.86:8099",
|
||||
web: "http://192.168.1.113:8099",
|
||||
|
||||
};
|
||||
// 生产环境
|
||||
const prod = {
|
||||
// common: "https://common-api.pickmall.cn",
|
||||
// buyer: "https://buyer-api.pickmall.cn",
|
||||
common: "http://192.168.1.200:8890",
|
||||
buyer: "http://192.168.1.200:8888",
|
||||
vlog: "http://192.168.1.200:8099",
|
||||
common: "http://192.168.1.113:8890",
|
||||
buyer: "http://192.168.1.113:8888",
|
||||
vlog: "http://192.168.1.86:8099",
|
||||
};
|
||||
|
||||
//默认生产环境
|
||||
|
||||
1
nativeResources/android/assets/agconnect-services.json
Normal file
1
nativeResources/android/assets/agconnect-services.json
Normal file
@ -0,0 +1 @@
|
||||
{"agcgw":{"url":"connect-drcn.dbankcloud.cn","backurl":"connect-drcn.hispace.hicloud.com","websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn","websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com"},"agcgw_all":{"SG":"connect-dra.dbankcloud.cn","SG_back":"connect-dra.hispace.hicloud.com","CN":"connect-drcn.dbankcloud.cn","CN_back":"connect-drcn.hispace.hicloud.com","RU":"connect-drru.hispace.dbankcloud.ru","RU_back":"connect-drru.hispace.dbankcloud.cn","DE":"connect-dre.dbankcloud.cn","DE_back":"connect-dre.hispace.hicloud.com"},"websocketgw_all":{"SG":"connect-ws-dra.hispace.dbankcloud.cn","SG_back":"connect-ws-dra.hispace.dbankcloud.com","CN":"connect-ws-drcn.hispace.dbankcloud.cn","CN_back":"connect-ws-drcn.hispace.dbankcloud.com","RU":"connect-ws-drru.hispace.dbankcloud.ru","RU_back":"connect-ws-drru.hispace.dbankcloud.cn","DE":"connect-ws-dre.hispace.dbankcloud.cn","DE_back":"connect-ws-dre.hispace.dbankcloud.com"},"client":{"cp_id":"30086000741655511","product_id":"388421841221950710","client_id":"1346412471476315840","client_secret":"F4B8602C5E2D5642872ED211C7478DB199EA3882FF02AD64113FCFD85CAE0E39","project_id":"388421841221950710","app_id":"110231111","api_key":"DQEDAKxxD0khNfIg6UkOoL08FvJ7BHkKnRi926D1isiHr1coC0avMtrtUxZSJOgu8nUoEWou+q/cZEY+O+5p40IarYKa/PD/JPoYMQ==","package_name":"cn.net.wzj.mall"},"oauth_client":{"client_id":"110231111","client_type":1},"app_info":{"app_id":"110231111","package_name":"cn.net.wzj.mall"},"service":{"analytics":{"collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn","collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn","collector_url_ru":"datacollector-drru.dt.dbankcloud.ru,datacollector-drru.dt.hicloud.com","collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn","resource_id":"p1","channel_id":""},"ml":{"mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn"},"cloudstorage":{"storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg":"https://ops-dra.agcstorage.link","storage_url_de":"https://ops-dre.agcstorage.link","storage_url_cn":"https://agc-storage-drcn.platform.dbankcloud.cn","storage_url_ru_back":"https://agc-storage-drru.cloud.huawei.ru","storage_url_sg_back":"https://agc-storage-dra.cloud.huawei.asia","storage_url_de_back":"https://agc-storage-dre.cloud.huawei.eu","storage_url_cn_back":"https://agc-storage-drcn.cloud.huawei.com.cn"},"search":{"url":"https://search-drcn.cloud.huawei.com"},"edukit":{"edu_url":"edukit.cloud.huawei.com.cn","dh_url":"edukit.cloud.huawei.com.cn"}},"region":"CN","configuration_version":"3.0","appInfos":[{"package_name":"cn.net.wzj.mall","client":{"app_id":"110231111"},"app_info":{"package_name":"cn.net.wzj.mall","app_id":"110231111"},"oauth_client":{"client_type":1,"client_id":"110231111"}}]}
|
||||
1
nativeResources/android/assets/timpush-configs.json
Normal file
1
nativeResources/android/assets/timpush-configs.json
Normal file
@ -0,0 +1 @@
|
||||
{"version":"1.0.1","cn.net.wzj.mall":{"manifestPlaceholders":{"VIVO_APPKEY":"ebe0d2ef18e69264e8ddfb48472cb3ec","VIVO_APPID":"105722088","HONOR_APPID":"104443878"},"xiaomiPushBussinessId":"41169","xiaomiPushAppId":"2882303761520283584","xiaomiPushAppKey":"5242028361584","oppoPushBussinessId":"41170","oppoPushAppKey":"d64af1f3a4c54c0dae37d556fde086af","oppoPushAppSecret":"f6458a874f9b432aaa7a4e4a7b782fd0","huaweiPushBussinessId":"41171","huaweiBadgeClassName":"","meizuPushBussinessId":"41176","meizuPushAppId":"153237","meizuPushAppKey":"e6cdd35fcd6b47679ccd9f5bba117578","vivoPushBussinessId":"41177","honorPushBussinessId":"41178"}}
|
||||
5
nativeResources/android/manifestPlaceholders.json
Normal file
5
nativeResources/android/manifestPlaceholders.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"VIVO_APPKEY": "ebe0d2ef18e69264e8ddfb48472cb3ec",
|
||||
"VIVO_APPID": "105722088",
|
||||
"HONOR_APPID": "104443878"
|
||||
}
|
||||
6
nativeResources/android/mcs-services.json
Normal file
6
nativeResources/android/mcs-services.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"developer_id":"109999867274",
|
||||
"app_id":"104443878",
|
||||
"package_name":"cn.net.wzj.mall",
|
||||
"version":"1.0"
|
||||
}
|
||||
3
nativeResources/ios/Resources/timpush-configs.json
Normal file
3
nativeResources/ios/Resources/timpush-configs.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"businessID": "45148"
|
||||
}
|
||||
4096
package-lock.json
generated
4096
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -1,10 +1,10 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^2.0.2-4050720250324001",
|
||||
"@tencentcloud/chat-uikit-uniapp": "^2.4.3",
|
||||
"@vue/runtime-core": "^3.5.13",
|
||||
"unplugin-vue2-script-setup": "^0.11.4",
|
||||
"vue": "^3.2.0",
|
||||
"ws": "^8.18.1"
|
||||
}
|
||||
}
|
||||
{
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^2.0.2-4050720250324001",
|
||||
"@tencentcloud/chat-uikit-uniapp": "^2.4.3",
|
||||
"@vue/runtime-core": "^3.5.13",
|
||||
"unplugin-vue2-script-setup": "^0.11.4",
|
||||
"vue": "^3.2.0",
|
||||
"ws": "^8.18.1"
|
||||
}
|
||||
}
|
||||
@ -1,375 +1,418 @@
|
||||
<template>
|
||||
<scroll-view class="prpage" scroll-y="true">
|
||||
<view class="line"></view>
|
||||
<!-- 进度条 -->
|
||||
<view class="progress" v-if="percentCompleted != 100">
|
||||
<progress :percent="percentCompleted" stroke-width="3" activeColor="#ef274d" backgroundColor="#F1F1F1" />
|
||||
<text class="progress-text">视频上传中,请耐心等待~~</text>
|
||||
<image class="progress-img" mode="aspectFit" src="/static/images/loading-4.gif" />
|
||||
</view>
|
||||
|
||||
<!-- 发布主体内容 -->
|
||||
<view class="main-body" v-if="percentCompleted == 100">
|
||||
<image class="main-body-img-m" v-if="tempCover" :src="tempCover" mode="widthFix" />
|
||||
<image class="main-body-img-m" v-if="!tempCover" src='/static/images/loading-4.gif' mode="aspectFit" />
|
||||
<view class="main-body-content">
|
||||
<view class="preplay-wrapper" @click="preview" @touchstart="touchstartPreplay"
|
||||
@touchend="touchendPreplay">
|
||||
<image class="preplay-icon" src="/static/images/btn-play.png" />
|
||||
<text class="preplay-text">预览视频</text>
|
||||
</view>
|
||||
<view class="choose-cover" @click="chooseCover">
|
||||
<text class="choose-cover-text">选择封面</text>
|
||||
</view>
|
||||
</view>
|
||||
<textarea class="vlog-content" placeholder-style="color: #9798a0;" placeholder="添加合适的描述内容~" :value="title"
|
||||
:model="title" maxlength="60" @input="typingContent" confirm-type="done"></textarea>
|
||||
<view class="mbtn" :class="{
|
||||
'btn-publish': !publishTouched,
|
||||
'btn-publish-touched': publishTouched,
|
||||
}" @touchstart="touchstartPublish" @touchend="touchendPublish" @click="doPublich">
|
||||
<text class="btn-text">发布视频</text>
|
||||
<template>
|
||||
<scroll-view
|
||||
class="prpage"
|
||||
scroll-y="true"
|
||||
>
|
||||
<view class="line"></view>
|
||||
<!-- 进度条 -->
|
||||
<view
|
||||
class="progress"
|
||||
v-if="percentCompleted != 100"
|
||||
>
|
||||
<progress
|
||||
:percent="percentCompleted"
|
||||
stroke-width="3"
|
||||
activeColor="#ef274d"
|
||||
backgroundColor="#F1F1F1"
|
||||
/>
|
||||
<text class="progress-text">视频上传中,请耐心等待~~</text>
|
||||
<image
|
||||
class="progress-img"
|
||||
mode="aspectFit"
|
||||
src="/static/images/loading-4.gif"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 发布主体内容 -->
|
||||
<view
|
||||
class="main-body"
|
||||
v-if="percentCompleted == 100"
|
||||
>
|
||||
<image
|
||||
class="main-body-img-m"
|
||||
v-if="tempCover"
|
||||
:src="tempCover"
|
||||
mode="widthFix"
|
||||
/>
|
||||
<image
|
||||
class="main-body-img-m"
|
||||
v-if="!tempCover"
|
||||
src="/static/images/loading-4.gif"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
<view class="main-body-content">
|
||||
<view
|
||||
class="preplay-wrapper"
|
||||
@click="preview"
|
||||
@touchstart="touchstartPreplay"
|
||||
@touchend="touchendPreplay"
|
||||
>
|
||||
<image
|
||||
class="preplay-icon"
|
||||
src="/static/images/btn-play.png"
|
||||
/>
|
||||
<text class="preplay-text">预览视频</text>
|
||||
</view>
|
||||
<view
|
||||
class="choose-cover"
|
||||
@click="chooseCover"
|
||||
>
|
||||
<text class="choose-cover-text">选择封面</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storage from "@/utils/storage.js"; //缓存
|
||||
// import {
|
||||
// graceNumber
|
||||
// } from '@/utils/tools.js'
|
||||
import api from "@/config/api.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
publishTouched: false,
|
||||
preplayTouched: false,
|
||||
tempFilePath: "",
|
||||
videoUrl: "",
|
||||
tempCover: "", // 视频封面
|
||||
title: "",
|
||||
width: 0,
|
||||
height: 0,
|
||||
percentCompleted: 0, // 进度
|
||||
};
|
||||
},
|
||||
onLoad(params) {
|
||||
let me = this;
|
||||
let vlogInfo = storage.getVlogUserInfo()
|
||||
// 上个页面传过来的文件事件对象, 其中包含了相册中选择的视频内容
|
||||
let fileObjectEvent = JSON.parse(params.fileObjectEvent);
|
||||
let times = new Date().getTime();
|
||||
var userId = vlogInfo.id;
|
||||
let nickname = vlogInfo.nickname;
|
||||
|
||||
let serverUrl = api.vlog;
|
||||
const uploadTask = uni.uploadFile({
|
||||
filePath: fileObjectEvent.tempFilePath,
|
||||
url: serverUrl + "/upload",
|
||||
name: 'file',
|
||||
formData: {
|
||||
filetype: 'video'
|
||||
},
|
||||
header: {
|
||||
headerUserId: userId,
|
||||
headerUserToken: storage.getVlogToken()
|
||||
},
|
||||
success: (f) => {
|
||||
console.log(f)
|
||||
let jsondata = f.data
|
||||
let data = JSON.parse(jsondata)
|
||||
let videoUrl = data.data;
|
||||
me.videoUrl = videoUrl;
|
||||
me.width = fileObjectEvent.width;
|
||||
me.height = fileObjectEvent.height;
|
||||
}
|
||||
})
|
||||
|
||||
uploadTask.onProgressUpdate((res) => {
|
||||
console.log('上传进度' + res.progress);
|
||||
// console.log('已经上传的数据长度' + res.totalBytesSent);
|
||||
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
|
||||
// 显示进度
|
||||
// let percentCompleted = Math.round(
|
||||
// (res.progress * 100) / res.total
|
||||
// );
|
||||
me.percentCompleted = res.progress
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
typingContent(e) {
|
||||
let event = e;
|
||||
this.title = e.detail.value;
|
||||
},
|
||||
doPublich() {
|
||||
if (this.title.length < 5) {
|
||||
uni.showToast({
|
||||
title: "请输入5个字以上的标题!",
|
||||
icon: "none",
|
||||
});
|
||||
return;
|
||||
}
|
||||
let me = this;
|
||||
let vlogInfo = storage.getVlogUserInfo()
|
||||
let userId = vlogInfo.id;
|
||||
let vlog = {
|
||||
vlogerId: userId,
|
||||
url: me.videoUrl,
|
||||
cover: me.tempCover || '',
|
||||
title: me.title,
|
||||
width: me.width,
|
||||
height: me.height,
|
||||
};
|
||||
|
||||
// 发布视频
|
||||
let serverUrl = api.vlog
|
||||
uni.request({
|
||||
method: "POST",
|
||||
header: {
|
||||
headerUserId: userId,
|
||||
headerUserToken: storage.getVlogToken(),
|
||||
},
|
||||
url: serverUrl + "/vlog/publish",
|
||||
data: vlog,
|
||||
success(result) {
|
||||
if (result.data.status == 200) {
|
||||
uni.showToast({
|
||||
title: result.data.msg,
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: "/pages/tabbar/user/my",
|
||||
});
|
||||
}, 2000);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.data.msg,
|
||||
icon: "none",
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
preview() {
|
||||
uni.navigateTo({
|
||||
url: "/pages/publish/preview?videoUrl=" +
|
||||
this.videoUrl +
|
||||
"&width=" +
|
||||
this.width +
|
||||
"&height=" +
|
||||
this.height,
|
||||
animationType: "slide-in-bottom",
|
||||
animationDuration: 500,
|
||||
});
|
||||
},
|
||||
|
||||
touchstartPreplay() {
|
||||
this.preplayTouched = true;
|
||||
},
|
||||
|
||||
touchendPreplay() {
|
||||
this.preplayTouched = false;
|
||||
},
|
||||
|
||||
touchstartPublish() {
|
||||
this.publishTouched = true;
|
||||
},
|
||||
|
||||
touchendPublish() {
|
||||
this.publishTouched = false;
|
||||
},
|
||||
|
||||
chooseCover() {
|
||||
let me = this;
|
||||
let vlogInfo = storage.getVlogUserInfo()
|
||||
let userId = vlogInfo.id;
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: "original",
|
||||
sourceType: ["album"],
|
||||
success(e) {
|
||||
me.tempCover = e.tempFilePaths[0]; //先在本地回显
|
||||
// 上传封面
|
||||
let serverUrl = api.vlog;
|
||||
uni.uploadFile({
|
||||
filePath: e.tempFilePaths[0],
|
||||
url: serverUrl + "/upload",
|
||||
formData: {
|
||||
filetype: 'video'
|
||||
},
|
||||
header: {
|
||||
headerUserId: userId,
|
||||
headerUserToken: storage.getVlogToken(),
|
||||
},
|
||||
name: "file",
|
||||
success(result) {
|
||||
let res = JSON.parse(result.data);
|
||||
console.log(res)
|
||||
if (res.status == 200) {
|
||||
let imageUrl = res.data;
|
||||
me.tempCover = imageUrl;
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
duration: 2000,
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: "none",
|
||||
duration: 3000,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.prpage {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #181b27;
|
||||
}
|
||||
|
||||
|
||||
.main-body-img-m {
|
||||
min-height: 400rpx;
|
||||
/* width: 750rpx; */
|
||||
border: 2rpx solid #545456;
|
||||
border-radius: 20rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.choose-cover-text {
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.choose-cover {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-left: 100rpx;
|
||||
margin-top: 10px;
|
||||
width: 200rpx;
|
||||
height: 100rpx;
|
||||
position: relative;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.preplay-icon {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preplay-text {
|
||||
color: #e6e6e6;
|
||||
font-size: 28rpx;
|
||||
align-items: center;
|
||||
margin-left: 15rpx;
|
||||
}
|
||||
|
||||
.preplay-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
padding: 6rpx 16rpx;
|
||||
width: 200rpx;
|
||||
}
|
||||
|
||||
.main-body-content {
|
||||
/* display: flex; */
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
|
||||
}
|
||||
|
||||
.vlog-content {
|
||||
margin-top: 30rpx;
|
||||
height: 200rpx;
|
||||
color: #000000;
|
||||
font-size: 16px;
|
||||
background-color: #ffffff;
|
||||
padding-left: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
padding-right: 20rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
color: #e6e6e6;
|
||||
font-size: 36rpx;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mbtn {
|
||||
margin-top: 30rpx;
|
||||
height: 90rpx;
|
||||
/* display: flex; */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 40rpx;
|
||||
border: transparent;
|
||||
}
|
||||
|
||||
.btn-publish {
|
||||
background-color: #ef274d;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-publish-touched {
|
||||
background-color: #de6981;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.main-body {
|
||||
margin-top: 20rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 1rpx;
|
||||
background-color: #393a41;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-top: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
color: #f1f1f1;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.progress-img {
|
||||
width: 600rpx;
|
||||
height: 600rpx;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
<textarea
|
||||
class="vlog-content"
|
||||
placeholder-style="color: #9798a0;"
|
||||
placeholder="添加合适的描述内容~"
|
||||
:value="title"
|
||||
:model="title"
|
||||
maxlength="60"
|
||||
@input="typingContent"
|
||||
confirm-type="done"
|
||||
></textarea>
|
||||
<view
|
||||
class="mbtn"
|
||||
:class="{
|
||||
'btn-publish': !publishTouched,
|
||||
'btn-publish-touched': publishTouched
|
||||
}"
|
||||
@touchstart="touchstartPublish"
|
||||
@touchend="touchendPublish"
|
||||
@click="doPublich"
|
||||
>
|
||||
<text class="btn-text">发布视频</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storage from '@/utils/storage.js'; //缓存
|
||||
// import {
|
||||
// graceNumber
|
||||
// } from '@/utils/tools.js'
|
||||
import api from '@/config/api.js';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
publishTouched: false,
|
||||
preplayTouched: false,
|
||||
tempFilePath: '',
|
||||
videoUrl: '',
|
||||
tempCover: '', // 视频封面
|
||||
title: '',
|
||||
width: 0,
|
||||
height: 0,
|
||||
percentCompleted: 0 // 进度
|
||||
};
|
||||
},
|
||||
onLoad(params) {
|
||||
let me = this;
|
||||
let vlogInfo = storage.getVlogUserInfo();
|
||||
// 上个页面传过来的文件事件对象, 其中包含了相册中选择的视频内容
|
||||
let fileObjectEvent = JSON.parse(params.fileObjectEvent);
|
||||
let times = new Date().getTime();
|
||||
var userId = vlogInfo.id;
|
||||
let nickname = vlogInfo.nickname;
|
||||
|
||||
let serverUrl = api.vlog;
|
||||
const uploadTask = uni.uploadFile({
|
||||
filePath: fileObjectEvent.tempFilePath,
|
||||
url: serverUrl + '/upload',
|
||||
name: 'file',
|
||||
formData: {
|
||||
filetype: 'video'
|
||||
},
|
||||
header: {
|
||||
headerUserId: userId,
|
||||
headerUserToken: storage.getVlogToken()
|
||||
},
|
||||
success: (f) => {
|
||||
console.log(f);
|
||||
let jsondata = f.data;
|
||||
let data = JSON.parse(jsondata);
|
||||
let videoUrl = data.data;
|
||||
me.videoUrl = videoUrl;
|
||||
me.width = fileObjectEvent.width;
|
||||
me.height = fileObjectEvent.height;
|
||||
}
|
||||
});
|
||||
|
||||
uploadTask.onProgressUpdate((res) => {
|
||||
console.log('上传进度' + res.progress);
|
||||
// console.log('已经上传的数据长度' + res.totalBytesSent);
|
||||
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
|
||||
// 显示进度
|
||||
// let percentCompleted = Math.round(
|
||||
// (res.progress * 100) / res.total
|
||||
// );
|
||||
me.percentCompleted = res.progress;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
typingContent(e) {
|
||||
let event = e;
|
||||
this.title = e.detail.value;
|
||||
},
|
||||
doPublich() {
|
||||
if (this.title.length < 5) {
|
||||
uni.showToast({
|
||||
title: '请输入5个字以上的标题!',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
let me = this;
|
||||
let vlogInfo = storage.getVlogUserInfo();
|
||||
let userId = vlogInfo.id;
|
||||
let vlog = {
|
||||
vlogerId: userId,
|
||||
url: me.videoUrl,
|
||||
cover: me.tempCover || '',
|
||||
title: me.title,
|
||||
width: me.width,
|
||||
height: me.height,
|
||||
cityCode: storage.getCityCode()
|
||||
};
|
||||
|
||||
// 发布视频
|
||||
let serverUrl = api.vlog;
|
||||
uni.request({
|
||||
method: 'POST',
|
||||
header: {
|
||||
headerUserId: userId,
|
||||
headerUserToken: storage.getVlogToken()
|
||||
},
|
||||
url: serverUrl + '/vlog/publish',
|
||||
data: vlog,
|
||||
success(result) {
|
||||
if (result.data.status == 200) {
|
||||
uni.showToast({
|
||||
title: result.data.msg,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
uni.switchTab({
|
||||
url: '/pages/me/me'
|
||||
});
|
||||
}, 2000);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.data.msg,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
preview() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/publish/preview?videoUrl=' + this.videoUrl + '&width=' + this.width + '&height=' + this.height,
|
||||
animationType: 'slide-in-bottom',
|
||||
animationDuration: 500
|
||||
});
|
||||
},
|
||||
|
||||
touchstartPreplay() {
|
||||
this.preplayTouched = true;
|
||||
},
|
||||
|
||||
touchendPreplay() {
|
||||
this.preplayTouched = false;
|
||||
},
|
||||
|
||||
touchstartPublish() {
|
||||
this.publishTouched = true;
|
||||
},
|
||||
|
||||
touchendPublish() {
|
||||
this.publishTouched = false;
|
||||
},
|
||||
|
||||
chooseCover() {
|
||||
let me = this;
|
||||
let vlogInfo = storage.getVlogUserInfo();
|
||||
let userId = vlogInfo.id;
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: 'original',
|
||||
sourceType: ['album'],
|
||||
success(e) {
|
||||
me.tempCover = e.tempFilePaths[0]; //先在本地回显
|
||||
// 上传封面
|
||||
let serverUrl = api.vlog;
|
||||
uni.uploadFile({
|
||||
filePath: e.tempFilePaths[0],
|
||||
url: serverUrl + '/upload',
|
||||
formData: {
|
||||
filetype: 'video'
|
||||
},
|
||||
header: {
|
||||
headerUserId: userId,
|
||||
headerUserToken: storage.getVlogToken()
|
||||
},
|
||||
name: 'file',
|
||||
success(result) {
|
||||
let res = JSON.parse(result.data);
|
||||
console.log(res);
|
||||
if (res.status == 200) {
|
||||
let imageUrl = res.data;
|
||||
me.tempCover = imageUrl;
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
duration: 2000
|
||||
});
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.prpage {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #181b27;
|
||||
}
|
||||
|
||||
.main-body-img-m {
|
||||
min-height: 400rpx;
|
||||
/* width: 750rpx; */
|
||||
border: 2rpx solid #545456;
|
||||
border-radius: 20rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.choose-cover-text {
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.choose-cover {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
margin-left: 100rpx;
|
||||
margin-top: 10px;
|
||||
width: 200rpx;
|
||||
height: 100rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.preplay-icon {
|
||||
width: 22rpx;
|
||||
height: 22rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preplay-text {
|
||||
color: #e6e6e6;
|
||||
font-size: 28rpx;
|
||||
align-items: center;
|
||||
margin-left: 15rpx;
|
||||
}
|
||||
|
||||
.preplay-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
padding: 6rpx 16rpx;
|
||||
width: 200rpx;
|
||||
}
|
||||
|
||||
.main-body-content {
|
||||
/* display: flex; */
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.vlog-content {
|
||||
margin-top: 30rpx;
|
||||
height: 200rpx;
|
||||
color: #000000;
|
||||
font-size: 16px;
|
||||
background-color: #ffffff;
|
||||
padding-left: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
padding-right: 20rpx;
|
||||
padding-bottom: 20rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.btn-text {
|
||||
color: #e6e6e6;
|
||||
font-size: 36rpx;
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.mbtn {
|
||||
margin-top: 30rpx;
|
||||
height: 90rpx;
|
||||
/* display: flex; */
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 40rpx;
|
||||
border: transparent;
|
||||
}
|
||||
|
||||
.btn-publish {
|
||||
background-color: #ef274d;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-publish-touched {
|
||||
background-color: #de6981;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-body {
|
||||
margin-top: 20rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 1rpx;
|
||||
background-color: #393a41;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-top: 60rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
color: #f1f1f1;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.progress-img {
|
||||
width: 600rpx;
|
||||
height: 600rpx;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,274 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- 这里是状态栏, 每个页面都需要有, 目的不让页面覆盖状态栏 -->
|
||||
<view :style="{ height: statusBarHeight + 'px' }"></view>
|
||||
<view class="big-search-wrapper">
|
||||
<image
|
||||
class="header-right-search icon-search"
|
||||
src="/static/images/icon-back.png"
|
||||
@click="back" />
|
||||
<view class="search-box">
|
||||
<view class="search-box-left">
|
||||
<image
|
||||
class="header-right-search search-image"
|
||||
src="/static/images/icon-search.png" />
|
||||
</view>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
:model="searchContent"
|
||||
:value="searchContent"
|
||||
@input="typingContent"
|
||||
placeholder="请输入内容~"
|
||||
maxlength="10"
|
||||
class="search-input" />
|
||||
|
||||
<view class="search-box-right">
|
||||
<image
|
||||
class="scan-image"
|
||||
src="/static/images/icon-scan-qrcode.png"
|
||||
@click="scan" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="btn" @click="doSearch">
|
||||
<text class="search-btn">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="history">
|
||||
<view
|
||||
v-for="(h, index) in historyList"
|
||||
:key="index"
|
||||
class="history-item-wrapper">
|
||||
<view class="time-and-text" @click="searchByHistory(h)">
|
||||
<image class="time-image" src="/static/images/icon-time.png" />
|
||||
<text class="history-text">{{ h }}</text>
|
||||
</view>
|
||||
<image
|
||||
class="delete-image"
|
||||
src="/static/images/icon-delete.png"
|
||||
@click="removeHistoryItem(index)" />
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="historyList.length == 0"
|
||||
class="clear-all-wrapper"
|
||||
@click="removeAllHistory">
|
||||
<text class="clear-all"></text>
|
||||
</view>
|
||||
<view v-else class="clear-all-wrapper" @click="removeAllHistory">
|
||||
<text class="clear-all">清除所有搜索记录</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let system = uni.getSystemInfoSync();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchContent: "",
|
||||
historyList: [],
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
this.statusBarHeight = system.statusBarHeight;
|
||||
|
||||
// 从本地缓存获得搜索的历史记录
|
||||
let historyListJSON = uni.getStorageSync("historyList");
|
||||
if (historyListJSON != null && historyListJSON != undefined) {
|
||||
this.historyList = JSON.parse(historyListJSON);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
});
|
||||
},
|
||||
scan() {
|
||||
uni.scanCode({
|
||||
success: (e) => {
|
||||
let result = e.result;
|
||||
let vlogId = JSON.parse(result).content;
|
||||
uni.navigateTo({
|
||||
url: "../vlog/vlog?vlogId=" + vlogId,
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
typingContent(e) {
|
||||
this.searchContent = e.detail.value;
|
||||
},
|
||||
searchByHistory(searchContent) {
|
||||
this.searchContent = searchContent;
|
||||
this.doSearch();
|
||||
},
|
||||
doSearch() {
|
||||
let me = this;
|
||||
let searchContent = this.searchContent;
|
||||
if (getApp().isStrEmpty(searchContent)) {
|
||||
uni.showToast({
|
||||
title: "搜索关键字为空!",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
this.searchContent = "";
|
||||
return;
|
||||
}
|
||||
|
||||
let tempList = this.historyList;
|
||||
// 判断搜索内容是否已经存在, 如果存在, 则移除
|
||||
for (let i = 0; i < tempList.length; i++) {
|
||||
let old = tempList[i];
|
||||
if (searchContent === old) {
|
||||
tempList.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tempList.unshift(searchContent);
|
||||
|
||||
// 如果超过10个, 则删除最后一项
|
||||
if (tempList.length > 10) {
|
||||
tempList.splice(10, 1);
|
||||
this.historyList = tempList;
|
||||
}
|
||||
|
||||
// 保存到本地缓存
|
||||
uni.setStorageSync("historyList", JSON.stringify(this.historyList));
|
||||
|
||||
// 跳转页面, 把搜索条件携带过去
|
||||
uni.navigateTo({
|
||||
url: "searchList?search=" + searchContent,
|
||||
});
|
||||
},
|
||||
|
||||
removeHistoryItem(index) {
|
||||
this.historyList.splice(index, 1);
|
||||
uni.setStorageSync("historyList", JSON.stringify(this.historyList));
|
||||
},
|
||||
|
||||
removeAllHistory() {
|
||||
this.historyList = [];
|
||||
uni.setStorageSync("historyList", JSON.stringify(this.historyList));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #181b27;
|
||||
|
||||
.big-search-wrapper {
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.header-right-search {
|
||||
height: 100rpx;
|
||||
}
|
||||
.icon-search {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
opacity: 0.8;
|
||||
align-self: center;
|
||||
}
|
||||
.search-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.search-box-left {
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-left-radius: 6rpx;
|
||||
border-bottom-left-radius: 6rpx;
|
||||
.search-image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
opacity: 0.8;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-input {
|
||||
width: 360rpx;
|
||||
background-color: #55565e;
|
||||
height: 60rpx;
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
}
|
||||
.search-box-right {
|
||||
padding: 0 16rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-right-radius: 6rpx;
|
||||
border-bottom-right-radius: 6rpx;
|
||||
.scan-image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
opacity: 0.8;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
.btn {
|
||||
align-self: center;
|
||||
.search-btn {
|
||||
color: #ffffff;
|
||||
font-size: 32rpx;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.history {
|
||||
.history-item-wrapper {
|
||||
padding: 16rpx 26rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.time-and-text {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 500rpx;
|
||||
.time-image {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
align-self: center;
|
||||
}
|
||||
.history-text {
|
||||
color: #ffffff;
|
||||
font-size: 30rpx;
|
||||
align-self: center;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
.delete-image {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
opacity: 0.9;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
.clear-all-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin-top: 40rpx;
|
||||
.clear-all {
|
||||
color: #f1f1f1;
|
||||
font-size: 28rpx;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
296
pages/search/search.vue
Executable file
296
pages/search/search.vue
Executable file
@ -0,0 +1,296 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- 这里是状态栏, 每个页面都需要有, 目的不让页面覆盖状态栏 -->
|
||||
<view :style="{ height: statusBarHeight + 'px' }"></view>
|
||||
<view class="big-search-wrapper">
|
||||
<image
|
||||
class="header-right-search icon-search"
|
||||
src="/static/images/icon-back.png"
|
||||
@click="back"
|
||||
/>
|
||||
<view class="search-box">
|
||||
<view class="search-box-left">
|
||||
<image
|
||||
class="header-right-search search-image"
|
||||
src="/static/images/icon-search.png"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
:model="searchContent"
|
||||
:value="searchContent"
|
||||
@input="typingContent"
|
||||
@confirm=""
|
||||
placeholder="请输入内容~"
|
||||
maxlength="10"
|
||||
class="search-input"
|
||||
/>
|
||||
|
||||
<!-- <view class="search-box-right">
|
||||
<image
|
||||
class="scan-image"
|
||||
src="/static/images/icon-scan-qrcode.png"
|
||||
@click="scan"
|
||||
/>
|
||||
</view> -->
|
||||
</view>
|
||||
<view
|
||||
class="sbtn"
|
||||
@click="doSearch"
|
||||
>
|
||||
搜索
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="history">
|
||||
<view
|
||||
v-for="(h, index) in historyList"
|
||||
:key="index"
|
||||
class="history-item-wrapper"
|
||||
>
|
||||
<view
|
||||
class="time-and-text"
|
||||
@click="searchByHistory(h)"
|
||||
>
|
||||
<image
|
||||
class="time-image"
|
||||
src="/static/images/icon-time.png"
|
||||
/>
|
||||
<text class="history-text">{{ h }}</text>
|
||||
</view>
|
||||
<image
|
||||
class="delete-image"
|
||||
src="/static/images/icon-delete.png"
|
||||
@click="removeHistoryItem(index)"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="historyList.length == 0"
|
||||
class="clear-all-wrapper"
|
||||
@click="removeAllHistory"
|
||||
>
|
||||
<text class="clear-all"></text>
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="clear-all-wrapper"
|
||||
@click="removeAllHistory"
|
||||
>
|
||||
<text class="clear-all">清除所有搜索记录</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let system = uni.getSystemInfoSync();
|
||||
import storage from '@/utils/storage.js'; //缓存
|
||||
import { isStrEmpty } from '@/utils/tools.js';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
searchContent: '',
|
||||
historyList: []
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
this.statusBarHeight = system.statusBarHeight;
|
||||
|
||||
// 从本地缓存获得搜索的历史记录
|
||||
let historyListJSON = uni.getStorageSync('historyList') || null;
|
||||
console.log(historyListJSON);
|
||||
if (historyListJSON != null && historyListJSON != undefined) {
|
||||
this.historyList = JSON.parse(historyListJSON);
|
||||
} else {
|
||||
this.historyList = [];
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
},
|
||||
scan() {
|
||||
// 扫描二维码跳转视频详情,先不做
|
||||
// uni.scanCode({
|
||||
// success: (e) => {
|
||||
// let result = e.result;
|
||||
// let vlogId = JSON.parse(result).content;
|
||||
// uni.navigateTo({
|
||||
// url: '../vlog/vlog?vlogId=' + vlogId
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
},
|
||||
typingContent(e) {
|
||||
this.searchContent = e.detail.value;
|
||||
},
|
||||
searchByHistory(searchContent) {
|
||||
console.log(searchContent);
|
||||
this.searchContent = searchContent;
|
||||
this.doSearch();
|
||||
},
|
||||
doSearch() {
|
||||
var searchContent = this.searchContent;
|
||||
if (isStrEmpty(this.searchContent)) {
|
||||
uni.showToast({
|
||||
title: '搜索关键字为空!',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
this.searchContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let tempList = this.historyList;
|
||||
// 判断搜索内容是否已经存在, 如果存在, 则移除
|
||||
for (let i = 0; i < tempList.length; i++) {
|
||||
let old = tempList[i];
|
||||
if (this.searchContent === old) {
|
||||
tempList.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tempList.unshift(searchContent);
|
||||
|
||||
// 如果超过10个, 则删除第一一项
|
||||
if (tempList.length > 10) {
|
||||
tempList.splice(0, 1);
|
||||
this.historyList = tempList;
|
||||
}
|
||||
|
||||
// 保存到本地缓存
|
||||
uni.setStorageSync('historyList', JSON.stringify(this.historyList));
|
||||
|
||||
// 跳转页面, 把搜索条件携带过去
|
||||
uni.navigateTo({
|
||||
url: 'searchList?search=' + searchContent
|
||||
});
|
||||
},
|
||||
|
||||
removeHistoryItem(index) {
|
||||
this.historyList.splice(index, 1);
|
||||
uni.setStorageSync('historyList', JSON.stringify(this.historyList));
|
||||
},
|
||||
|
||||
removeAllHistory() {
|
||||
this.historyList = [];
|
||||
uni.setStorageSync('historyList', JSON.stringify(this.historyList));
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scope>
|
||||
.page {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #181b27;
|
||||
|
||||
.big-search-wrapper {
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.header-right-search {
|
||||
height: 100rpx;
|
||||
}
|
||||
.icon-search {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.search-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.search-box-left {
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-left-radius: 6rpx;
|
||||
border-bottom-left-radius: 6rpx;
|
||||
.search-image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-input {
|
||||
width: 410rpx;
|
||||
height: 50rpx;
|
||||
background-color: #55565e;
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
border-top-right-radius: 6rpx;
|
||||
border-bottom-right-radius: 6rpx;
|
||||
}
|
||||
.search-box-right {
|
||||
padding: 0 16rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-right-radius: 6rpx;
|
||||
border-bottom-right-radius: 6rpx;
|
||||
.scan-image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
.sbtn {
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.history {
|
||||
.history-item-wrapper {
|
||||
padding: 16rpx 26rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.time-and-text {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 500rpx;
|
||||
.time-image {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
.history-text {
|
||||
color: #ffffff;
|
||||
font-size: 30rpx;
|
||||
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
.delete-image {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
.clear-all-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
margin-top: 40rpx;
|
||||
.clear-all {
|
||||
color: #f1f1f1;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,260 +0,0 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view :style="{ height: statusBarHeight + 'px' }">
|
||||
<!-- 这里是状态栏, 每个页面都需要有, 目的不让页面覆盖状态栏 -->
|
||||
</view>
|
||||
<view class="big-search-wrapper">
|
||||
<image
|
||||
class="header-right-search icon-search"
|
||||
src="/static/images/icon-back.png"
|
||||
@click="back" />
|
||||
<view class="search-box">
|
||||
<view class="search-box-left">
|
||||
<image
|
||||
class="header-right-search search-image"
|
||||
src="/static/images/icon-search.png" />
|
||||
</view>
|
||||
<input
|
||||
type="text"
|
||||
:model="searchContent"
|
||||
:value="searchContent"
|
||||
@input="typingContent"
|
||||
placeholder="请输入内容~"
|
||||
maxlength="10"
|
||||
class="search-input" />
|
||||
</view>
|
||||
<view class="btn" @click="doSearch">
|
||||
<text class="search-btn">搜索</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="waterfall-wrapper" :style="{ height: screenHeight + 'px' }">
|
||||
<waterfall
|
||||
:style="{ height: screenHeight + 'px' }"
|
||||
column-count="2"
|
||||
column-width="auto"
|
||||
column-gap="2rpx"
|
||||
left-gap="4rpx"
|
||||
right-gap="4rpx">
|
||||
<cell v-for="(vlog, index) in waterList" :key="index">
|
||||
<view class="every-single-video" @appear="appearVlog(index)">
|
||||
<image
|
||||
:src="vlog.cover"
|
||||
mode="aspectFill"
|
||||
class="half-cover"
|
||||
@click="goToVlog(vlog.vlogId)" />
|
||||
</view>
|
||||
</cell>
|
||||
</waterfall>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let system = uni.getSystemInfoSync();
|
||||
let app = getApp();
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
screenHeight: 0,
|
||||
statusBarHeight: 0,
|
||||
waterList: [],
|
||||
page: 0,
|
||||
totalPage: 0,
|
||||
search: "",
|
||||
searchContent: "",
|
||||
};
|
||||
},
|
||||
onLoad(params) {
|
||||
uni.showLoading({
|
||||
title: "正在获取!",
|
||||
});
|
||||
this.statusBarHeight = system.statusBarHeight;
|
||||
let screenHeight = system.safeArea.bottom;
|
||||
this.screenHeight = screenHeight;
|
||||
this.searchContent = params.search
|
||||
// 搜索的关键字
|
||||
let search = params.search;
|
||||
this.search = search;
|
||||
this.fetchList(0);
|
||||
},
|
||||
onShow() {},
|
||||
methods: {
|
||||
doSearch() {
|
||||
let me = this;
|
||||
let searchContent = this.searchContent;
|
||||
if (getApp().isStrEmpty(searchContent)) {
|
||||
uni.showToast({
|
||||
title: "搜索为空!",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
this.searchContent = "";
|
||||
return;
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: "searchList?search=" + searchContent,
|
||||
});
|
||||
},
|
||||
typingContent(e) {
|
||||
this.searchContent = e.detail.value;
|
||||
},
|
||||
back() {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
});
|
||||
},
|
||||
loadMore() {
|
||||
if (this.page >= this.totalPage) {
|
||||
return;
|
||||
} else {
|
||||
this.fetchList(this.page);
|
||||
}
|
||||
},
|
||||
fetchList(page) {
|
||||
let me = this;
|
||||
page = page + 1;
|
||||
let search = me.search;
|
||||
let userInfo = getApp().getUserInfoSession();
|
||||
let userId = "";
|
||||
if (!app.isStrEmpty(userInfo)) {
|
||||
userId = userInfo.id;
|
||||
}
|
||||
|
||||
let serverUrl = app.globalData.serverUrl;
|
||||
uni.request({
|
||||
method: "GET",
|
||||
url:
|
||||
serverUrl +
|
||||
"/vlog/indexList?userId=" +
|
||||
userId +
|
||||
"&search=" +
|
||||
search +
|
||||
"&page=" +
|
||||
page +
|
||||
"&pageSize=10",
|
||||
success(result) {
|
||||
if (result.data.status == 206) {
|
||||
uni.hideLoading();
|
||||
let waterList = result.data.data.rows;
|
||||
let totalPage = result.data.data.total;
|
||||
me.waterList = waterList;
|
||||
me.page = page;
|
||||
me.totalPage = totalPage;
|
||||
if (
|
||||
waterList == null ||
|
||||
waterList == undefined ||
|
||||
waterList.length == 0
|
||||
) {
|
||||
uni.showToast({
|
||||
title: "没有结果~",
|
||||
icon: "none",
|
||||
duration: 2000,
|
||||
});
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
goToVlog(vlogId) {
|
||||
uni.navigateTo({
|
||||
url: "../vlog/vlog?vlogId=" + vlogId,
|
||||
});
|
||||
},
|
||||
|
||||
// 每个vlog出现都会触发
|
||||
appearVlog(index, e) {
|
||||
let me = this;
|
||||
// 如果最后一个vlog出现, 则加载更多
|
||||
if (index == me.waterList.length - 1) {
|
||||
me.loadMore();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #181b27;
|
||||
|
||||
.big-search-wrapper {
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.header-right-search {
|
||||
height: 100rpx;
|
||||
}
|
||||
.icon-search {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
opacity: 0.8;
|
||||
align-self: center;
|
||||
}
|
||||
.search-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.search-box-left {
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-left-radius: 6rpx;
|
||||
border-bottom-left-radius: 6rpx;
|
||||
.search-image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
opacity: 0.8;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-input {
|
||||
width: 440rpx;
|
||||
background-color: #55565e;
|
||||
height: 60rpx;
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
border-top-right-radius: 6rpx;
|
||||
border-bottom-right-radius: 6rpx;
|
||||
}
|
||||
.btn {
|
||||
align-self: center;
|
||||
.search-btn {
|
||||
color: #ffffff;
|
||||
font-size: 32rpx;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.waterfall-wrapper {
|
||||
background-color: #181b27;
|
||||
.every-single-video {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 10rpx;
|
||||
.half-cover {
|
||||
background-color: #000000;
|
||||
height: 600rpx;
|
||||
width: 365rpx;
|
||||
border-top-left-radius: 10rpx;
|
||||
border-top-right-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
399
pages/search/searchList.vue
Executable file
399
pages/search/searchList.vue
Executable file
@ -0,0 +1,399 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<view :style="{ height: statusBarHeight + 'px' }">
|
||||
<!-- 这里是状态栏, 每个页面都需要有, 目的不让页面覆盖状态栏 -->
|
||||
</view>
|
||||
<view class="big-search-wrapper">
|
||||
<image
|
||||
class="header-right-search icon-search"
|
||||
src="/static/images/icon-back.png"
|
||||
@click="back"
|
||||
/>
|
||||
<view class="search-box">
|
||||
<view class="search-box-left">
|
||||
<image
|
||||
class="header-right-search search-image"
|
||||
src="/static/images/icon-search.png"
|
||||
/>
|
||||
</view>
|
||||
<input
|
||||
type="text"
|
||||
:model="searchContent"
|
||||
:value="searchContent"
|
||||
@input="typingContent"
|
||||
placeholder="请输入内容~"
|
||||
maxlength="10"
|
||||
class="search-input"
|
||||
/>
|
||||
</view>
|
||||
<view
|
||||
class="sbtn"
|
||||
@click="doSearch"
|
||||
>
|
||||
搜索
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mainCont">
|
||||
<view
|
||||
class="wrap"
|
||||
:style="{ height: screenHeight - statusBarHeight - 50 + 'px' }"
|
||||
>
|
||||
<view class="u-tabs-box">
|
||||
<u-tabs-swiper
|
||||
bgColor=" #F5F5F5"
|
||||
activeColor="#FF3229"
|
||||
ref="tabs"
|
||||
:list="list"
|
||||
:current="current"
|
||||
@change="change"
|
||||
:is-scroll="false"
|
||||
swiperWidth="750"
|
||||
font-size="30rpx"
|
||||
barWidth="24"
|
||||
barHeight="8"
|
||||
></u-tabs-swiper>
|
||||
</view>
|
||||
<swiper
|
||||
class="swiper-box"
|
||||
:current="swiperCurrent"
|
||||
@transition="transition"
|
||||
@animationfinish="animationfinish"
|
||||
>
|
||||
<swiper-item class="swiper-item">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="no-scrollbar"
|
||||
style="height: 100%; width: 100%"
|
||||
@scrolltolower="reachBottom"
|
||||
>
|
||||
<view class="page-box">
|
||||
<!--视频-->
|
||||
<search-vd
|
||||
ref="vd"
|
||||
:keywords="searchContent"
|
||||
></search-vd>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
|
||||
<swiper-item class="swiper-item">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="no-scrollbar"
|
||||
style="height: 100%; width: 100%"
|
||||
@scrolltolower="reachBottom"
|
||||
>
|
||||
<view class="page-box">
|
||||
<!--商品-->
|
||||
<shop
|
||||
ref="shop"
|
||||
:keywords="searchContent"
|
||||
></shop>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
|
||||
<swiper-item class="swiper-item">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="no-scrollbar"
|
||||
style="height: 100%; width: 100%"
|
||||
@scrolltolower="reachBottom"
|
||||
>
|
||||
<view class="page-box">
|
||||
<!--用户-->
|
||||
<user
|
||||
ref="user"
|
||||
:keywords="searchContent"
|
||||
></user>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
|
||||
<swiper-item class="swiper-item">
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="no-scrollbar"
|
||||
style="height: 100%; width: 100%"
|
||||
@scrolltolower="reachBottom"
|
||||
>
|
||||
<view class="page-box">
|
||||
<!--团购-->
|
||||
<tuangou
|
||||
ref="tuangou"
|
||||
:keywords="searchContent"
|
||||
></tuangou>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
|
||||
<!-- <view class="page-footer">
|
||||
<view class="contract-button">
|
||||
自定义底部栏
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
let system = uni.getSystemInfoSync();
|
||||
console.log(system);
|
||||
import { isStrEmpty } from '@/utils/tools.js';
|
||||
import storage from '@/utils/storage.js'; //缓存
|
||||
import searchVd from './searchVd.vue';
|
||||
import shop from './shop';
|
||||
import user from './user';
|
||||
import tuangou from './tuangou';
|
||||
export default {
|
||||
components: {
|
||||
searchVd,
|
||||
shop,
|
||||
user,
|
||||
tuangou
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
screenHeight: 0,
|
||||
statusBarHeight: 0,
|
||||
search: '',
|
||||
searchContent: '',
|
||||
// tabs
|
||||
list: [
|
||||
{
|
||||
name: '视频'
|
||||
},
|
||||
{
|
||||
name: '商品'
|
||||
},
|
||||
{
|
||||
name: '用户'
|
||||
},
|
||||
{
|
||||
name: '团购'
|
||||
}
|
||||
],
|
||||
listValue: ['vd', 'shop', 'user', 'tuangou'],
|
||||
current: 0,
|
||||
swiperCurrent: 0,
|
||||
dx: 0
|
||||
// tabs-end
|
||||
};
|
||||
},
|
||||
onLoad(params) {
|
||||
this.statusBarHeight = system.statusBarHeight;
|
||||
let screenHeight = system.safeArea.bottom;
|
||||
this.screenHeight = screenHeight;
|
||||
// 搜索的关键字
|
||||
let search = params.search || ''.trim();
|
||||
this.searchContent = params.search;
|
||||
},
|
||||
watch: {
|
||||
current(n) {
|
||||
this.initCurrentData();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 初始化数据
|
||||
initCurrentData() {
|
||||
console.log(this.current);
|
||||
var prop = this.listValue[this.current];
|
||||
var dom = this.$refs[prop];
|
||||
var child = dom.search; //子组件内部的关键字
|
||||
console.log('子关键字:' + child);
|
||||
var flag = dom.flag; // 子组件内部索引
|
||||
var parent = this.searchContent;
|
||||
console.log('fu关键字:' + parent);
|
||||
if (parent != child && this.swiperCurrent == flag && this.searchContent != '') {
|
||||
dom.initData();
|
||||
}
|
||||
},
|
||||
// tab栏切换
|
||||
change(index) {
|
||||
this.swiperCurrent = index;
|
||||
},
|
||||
transition({ detail: { dx } }) {
|
||||
this.$refs.tabs.setDx(dx);
|
||||
},
|
||||
animationfinish({ detail: { current } }) {
|
||||
this.$refs.tabs.setFinishCurrent(current);
|
||||
this.swiperCurrent = current;
|
||||
this.current = current;
|
||||
},
|
||||
reachBottom() {
|
||||
console.log('触底' + this.current);
|
||||
var prop = this.listValue[this.current];
|
||||
var dom = this.$refs[prop];
|
||||
dom.getData();
|
||||
},
|
||||
doSearch() {
|
||||
let me = this;
|
||||
let searchContent = this.searchContent;
|
||||
if (isStrEmpty(searchContent)) {
|
||||
uni.showToast({
|
||||
title: '搜索为空!',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
this.searchContent = '';
|
||||
return;
|
||||
} else {
|
||||
this.initCurrentData();
|
||||
}
|
||||
},
|
||||
typingContent(e) {
|
||||
this.searchContent = e.detail.value || ''.trim();
|
||||
},
|
||||
back() {
|
||||
uni.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.page {
|
||||
// position: absolute;
|
||||
// left: 0;
|
||||
// right: 0;
|
||||
// top: 0;
|
||||
// bottom: 0;
|
||||
background-color: #181b27;
|
||||
|
||||
.big-search-wrapper {
|
||||
padding: 14px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.header-right-search {
|
||||
height: 50px;
|
||||
}
|
||||
.icon-search {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.search-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.search-box-left {
|
||||
padding: 0 10rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-left-radius: 6rpx;
|
||||
border-bottom-left-radius: 6rpx;
|
||||
.search-image {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
.search-input {
|
||||
width: 410rpx;
|
||||
height: 25px;
|
||||
background-color: #55565e;
|
||||
font-size: 28rpx;
|
||||
color: #ffffff;
|
||||
border-top-right-radius: 6rpx;
|
||||
border-bottom-right-radius: 6rpx;
|
||||
}
|
||||
.search-box-right {
|
||||
padding: 0 16rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: #55565e;
|
||||
border-top-right-radius: 6rpx;
|
||||
border-bottom-right-radius: 6rpx;
|
||||
.scan-image {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
.sbtn {
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
// 隐藏ios端滚动条
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
width: 0 !important;
|
||||
height: 0 !important;
|
||||
-webkit-appearance: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
//
|
||||
.mainCont {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.u-tabs-box {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.page-box {
|
||||
width: 710rpx;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.swiper-box {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.swiper-item {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// footer config
|
||||
// .page-footer {
|
||||
// width: 750rpx;
|
||||
// height: 128rpx;
|
||||
// background: #ffffff;
|
||||
// box-shadow: 0rpx -4rpx 16rpx rgba(219, 208, 208, 0.61);
|
||||
// opacity: 1;
|
||||
// border-radius: 0rpx;
|
||||
|
||||
// .contract-button {
|
||||
// width: 686rpx;
|
||||
// height: 80rpx;
|
||||
|
||||
// margin-top: 24rpx;
|
||||
// margin-left: 32rpx;
|
||||
|
||||
// font-size: 34rpx;
|
||||
// font-family: PingFang SC;
|
||||
// font-weight: 500;
|
||||
|
||||
// text-align: center;
|
||||
|
||||
// line-height: 80rpx;
|
||||
// color: #ffffff;
|
||||
// letter-spacing: 5rpx;
|
||||
|
||||
// background: linear-gradient(137deg, #ff3229 0%, #ff7b59 100%);
|
||||
// opacity: 1;
|
||||
// border-radius: 40rpx;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
</style>
|
||||
243
pages/search/searchVd.vue
Normal file
243
pages/search/searchVd.vue
Normal file
@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<view class="wrap">
|
||||
<view v-if="flowList.length">
|
||||
<u-waterfall
|
||||
v-model="flowList"
|
||||
ref="uWaterfall"
|
||||
idKey="vlogId"
|
||||
>
|
||||
<template v-slot:left="{ leftList }">
|
||||
<view
|
||||
class="demo-warter"
|
||||
v-for="(item, index) in leftList"
|
||||
:key="index"
|
||||
@click="goToVlog(item.vlogId)"
|
||||
>
|
||||
<u-lazy-load
|
||||
border-radius="10"
|
||||
:image="item.cover || item.firstFrameImg"
|
||||
:index="index"
|
||||
></u-lazy-load>
|
||||
<view class="content">
|
||||
{{ item.content }}
|
||||
</view>
|
||||
<view class="flxbox">
|
||||
<view class="bottom-info">
|
||||
<u-image
|
||||
width="30rpx"
|
||||
height="30rpx"
|
||||
:src="item.vlogerFace"
|
||||
loading-icon="/static/missing-face.png"
|
||||
error-icon="/static/missing-face.png"
|
||||
shape="circle"
|
||||
style="display: flex; align-items: center"
|
||||
></u-image>
|
||||
<view class="showOne ml">{{ item.vlogerName }}</view>
|
||||
</view>
|
||||
<view class="bottom-info">
|
||||
<image
|
||||
style="width: 20rpx; height: 20rpx"
|
||||
src="/static/images/icon-comment-unlike.png"
|
||||
></image>
|
||||
<view class="ml">{{ getGraceNumber(item.likeCounts) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<template v-slot:right="{ rightList }">
|
||||
<view
|
||||
class="demo-warter"
|
||||
v-for="(item, index) in rightList"
|
||||
:key="index"
|
||||
@click="goToVlog(item.vlogId)"
|
||||
>
|
||||
<u-lazy-load
|
||||
border-radius="10"
|
||||
:image="item.cover || item.firstFrameImg"
|
||||
:index="index"
|
||||
></u-lazy-load>
|
||||
<view class="content">
|
||||
{{ item.content }}
|
||||
</view>
|
||||
<view class="flxbox">
|
||||
<view class="bottom-info">
|
||||
<u-image
|
||||
width="30rpx"
|
||||
height="30rpx"
|
||||
loading-icon="/static/missing-face.png"
|
||||
error-icon="/static/missing-face.png"
|
||||
:src="item.vlogerFace"
|
||||
shape="circle"
|
||||
style="display: flex; align-items: center"
|
||||
></u-image>
|
||||
<view class="showOne ml">{{ item.vlogerName }}</view>
|
||||
</view>
|
||||
<view class="bottom-info">
|
||||
<image
|
||||
style="width: 20rpx; height: 20rpx"
|
||||
src="/static/images/icon-comment-unlike.png"
|
||||
></image>
|
||||
<view class="ml">{{ getGraceNumber(item.likeCounts) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</u-waterfall>
|
||||
<u-loadmore
|
||||
style="padding: 10px 0"
|
||||
bg-color="#f8f8f8"
|
||||
:status="loadStatus"
|
||||
@loadmore="getData"
|
||||
></u-loadmore>
|
||||
</view>
|
||||
|
||||
<u-empty
|
||||
class="mt20"
|
||||
v-else
|
||||
text="暂无数据"
|
||||
mode="data"
|
||||
></u-empty>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { vlogList } from '@/api/vlog';
|
||||
import { graceNumber, isStrEmpty } from '@/utils/tools.js';
|
||||
import storage from '@/utils/storage.js'; //缓存
|
||||
export default {
|
||||
props: {
|
||||
keywords: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: 0, // 在tabs中的索引
|
||||
loadStatus: 'loadmore',
|
||||
flowList: [],
|
||||
page: 0,
|
||||
totalPage: 0,
|
||||
search: ''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
initData() {
|
||||
this.clear();
|
||||
this.search = this.keywords;
|
||||
this.page = 0;
|
||||
this.totalPage = 0;
|
||||
this.flowList = [];
|
||||
this.loadStatus = 'loadmore';
|
||||
this.getData();
|
||||
},
|
||||
async getData() {
|
||||
try {
|
||||
if (this.loadStatus !== 'loadmore') return;
|
||||
let me = this;
|
||||
me.loadStatus = 'loading';
|
||||
let page = me.page + 1;
|
||||
let keywords = me.search;
|
||||
let userInfo = storage.getVlogUserInfo();
|
||||
let userId = '';
|
||||
if (userInfo != null) {
|
||||
userId = userInfo.id;
|
||||
}
|
||||
var result = await vlogList(page, 10, userId, '', keywords);
|
||||
console.log(result);
|
||||
if (result.data.status == 200) {
|
||||
let flowList = result.data.data.rows;
|
||||
let totalPage = result.data.data.total;
|
||||
me.flowList = me.flowList.concat(flowList);
|
||||
me.page = page;
|
||||
me.totalPage = totalPage;
|
||||
if (page >= totalPage) {
|
||||
me.loadStatus = 'nomore';
|
||||
} else {
|
||||
me.loadStatus = 'loadmore';
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
this.loadStatus = 'nomore';
|
||||
}
|
||||
},
|
||||
// 把超过1000或10000的数字调整,比如1.3k/6.8w
|
||||
getGraceNumber(num) {
|
||||
return graceNumber(num);
|
||||
},
|
||||
goToVlog(vlogId) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/me/vlog?vlogId=' + vlogId
|
||||
});
|
||||
},
|
||||
remove(id) {
|
||||
this.$refs.uWaterfall.remove(id);
|
||||
},
|
||||
clear() {
|
||||
var dom = this.$refs.uWaterfall;
|
||||
if (dom) {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mt20 {
|
||||
margin-top: 20% !important;
|
||||
}
|
||||
.demo-warter {
|
||||
border-radius: 8px;
|
||||
margin: 5px;
|
||||
background-color: #ffffff;
|
||||
padding: 8px;
|
||||
position: relative;
|
||||
max-width: 329rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.u-close {
|
||||
position: absolute;
|
||||
top: 32rpx;
|
||||
right: 32rpx;
|
||||
}
|
||||
|
||||
.showOne {
|
||||
width: 200rpx;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.content {
|
||||
// width: 329rpx;
|
||||
font-size: 28rpx;
|
||||
color: #000;
|
||||
margin-top: 5px;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 3; /* 最多显示三行 */
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.flxbox {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.bottom-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 22rpx;
|
||||
color: $u-tips-color;
|
||||
}
|
||||
.ml {
|
||||
display: block;
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
818
pages/search/shop.vue
Normal file
818
pages/search/shop.vue
Normal file
@ -0,0 +1,818 @@
|
||||
<template>
|
||||
<view class="wrap">
|
||||
<view v-if="flowList.length">
|
||||
<view class="goods-list">
|
||||
<view
|
||||
v-for="(item, index) in flowList"
|
||||
:key="index"
|
||||
class="goods-item"
|
||||
>
|
||||
<view
|
||||
class="image-wrapper"
|
||||
@click="navigateToDetailPage(item)"
|
||||
>
|
||||
<image
|
||||
:src="removeOssStyle(item.content.thumbnail)"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="goods-detail">
|
||||
<div
|
||||
class="title"
|
||||
@click="navigateToDetailPage(item)"
|
||||
>
|
||||
{{ item.content.goodsName }}
|
||||
</div>
|
||||
<view
|
||||
class="price-box"
|
||||
@click="navigateToDetailPage(item)"
|
||||
>
|
||||
<div
|
||||
class="price"
|
||||
v-if="item.content.price != undefined"
|
||||
>
|
||||
¥
|
||||
<span>{{ formatPrice(item.content.price)[0] }}</span>
|
||||
.{{ formatPrice(item.content.price)[1] }}
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<div
|
||||
class="promotion"
|
||||
@click="navigateToDetailPage(item)"
|
||||
>
|
||||
<div
|
||||
v-for="(promotionItem, promotionIndex) in getPromotion(item)"
|
||||
:key="promotionIndex"
|
||||
>
|
||||
<span v-if="promotionItem.indexOf('COUPON') != -1">劵</span>
|
||||
<span v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span>
|
||||
<span v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="count-config"
|
||||
@click="navigateToDetailPage(item)"
|
||||
>
|
||||
<span>已售 {{ item.content.buyCount || '0' }}</span>
|
||||
<span>{{ item.content.commentNum || '0' }}条评论</span>
|
||||
</div>
|
||||
<div
|
||||
class="store-seller-name"
|
||||
@click="navigateToStoreDetailPage(item)"
|
||||
>
|
||||
<div class="text-hidden">
|
||||
<u-tag
|
||||
style="margin-right: 10rpx"
|
||||
size="mini"
|
||||
mode="dark"
|
||||
v-if="item.selfOperated"
|
||||
text="自营"
|
||||
type="error"
|
||||
/>
|
||||
<span>{{ item.content.storeName || '暂无' }}</span>
|
||||
</div>
|
||||
<span>
|
||||
<u-icon name="arrow-right"></u-icon>
|
||||
</span>
|
||||
</div>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<u-loadmore
|
||||
style="padding: 10px 0"
|
||||
bg-color="#f8f8f8"
|
||||
:status="loadStatus"
|
||||
@loadmore="getData"
|
||||
></u-loadmore>
|
||||
</view>
|
||||
<u-empty
|
||||
v-else
|
||||
class="mt20"
|
||||
style="margin-top: 20%"
|
||||
text="暂无数据"
|
||||
mode="data"
|
||||
></u-empty>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getGoodsList } from '@/api/goods.js';
|
||||
export default {
|
||||
props: {
|
||||
keywords: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: 1, // 在tabs中的索引
|
||||
loadStatus: 'loadmore',
|
||||
flowList: [],
|
||||
page: 0,
|
||||
totalPage: 0,
|
||||
search: ''
|
||||
// 查询商品参数
|
||||
// params: {
|
||||
// pageNumber: 1,
|
||||
// pageSize: 10,
|
||||
// keyword: "",
|
||||
// }
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
if (this.loadStatus != 'loadmore') return;
|
||||
console.log('加载商品数据');
|
||||
this.page += 1;
|
||||
var params = {
|
||||
pageNumber: this.page,
|
||||
pageSize: 10,
|
||||
keyword: this.search
|
||||
};
|
||||
var res = await getGoodsList(params);
|
||||
console.log(res);
|
||||
if (res.data.result.content.length < 10) {
|
||||
this.loadStatus = 'nomore';
|
||||
} else {
|
||||
this.loadStatus = 'loadmore';
|
||||
}
|
||||
this.flowList.push(...res.data.result.content);
|
||||
},
|
||||
initData() {
|
||||
this.search = this.keywords;
|
||||
this.page = 0;
|
||||
this.totalPage = 0;
|
||||
this.flowList = [];
|
||||
this.loadStatus = 'loadmore';
|
||||
console.log('初始化商品数据');
|
||||
this.getData();
|
||||
},
|
||||
formatPrice(val) {
|
||||
if (typeof val == 'undefined') {
|
||||
return val;
|
||||
}
|
||||
return val.toFixed(2).split('.');
|
||||
},
|
||||
// 数据去重一下 只显示一次 减免 劵 什么的
|
||||
getPromotion(item) {
|
||||
if (item.promotionMap) {
|
||||
let array = [];
|
||||
Object.keys(item.promotionMap).forEach((child) => {
|
||||
if (!array.includes(child.split('-')[0])) {
|
||||
array.push(child.split('-')[0]);
|
||||
}
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
},
|
||||
removeOssStyle(url) {
|
||||
return url.split('?')[0];
|
||||
},
|
||||
// 跳转到商品详情
|
||||
navigateToDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${item.content.id}&goodsId=${item.content.goodsId}`
|
||||
});
|
||||
},
|
||||
// 跳转地址
|
||||
navigateToStoreDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/shopPage?id=${item.content.storeId}`
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mt20 {
|
||||
margin-top: 20% !important;
|
||||
}
|
||||
.sort-active {
|
||||
border: 1px solid $light-color;
|
||||
color: $light-color;
|
||||
background: $price-light-color !important;
|
||||
}
|
||||
|
||||
.oldKeyList {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 20rpx 3%;
|
||||
> .oldKeyItem {
|
||||
padding: 4rpx 24rpx;
|
||||
background: #f0f2f5;
|
||||
margin-right: 20rpx;
|
||||
max-width: 200rpx;
|
||||
border-radius: 100px;
|
||||
font-size: 24rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.promotion {
|
||||
margin-top: 4rpx;
|
||||
display: flex;
|
||||
div {
|
||||
span {
|
||||
font-size: 24rpx;
|
||||
color: $light-color;
|
||||
margin-right: 10rpx;
|
||||
padding: 0 4rpx;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.status_bar {
|
||||
height: var(--status-bar-height);
|
||||
background: #fff !important;
|
||||
width: 100%;
|
||||
}
|
||||
page {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
.sort-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
background: #f7f7f7;
|
||||
.sort-list {
|
||||
margin: 20rpx 0;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
> .sort-item {
|
||||
> .sort-title {
|
||||
margin: 20rpx 0;
|
||||
font-size: 26rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.null-view {
|
||||
height: 140rpx;
|
||||
}
|
||||
|
||||
.sort-btn {
|
||||
display: flex;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
border-top: 1px solid #f7f7f7;
|
||||
height: 100rpx;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
align-items: center;
|
||||
> view {
|
||||
width: 50%;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 1000px;
|
||||
}
|
||||
> .sort-btn-repick {
|
||||
border: 1px solid #ededed;
|
||||
}
|
||||
> .sort-btn-confim {
|
||||
color: #fff;
|
||||
background-image: linear-gradient(90deg, #ff6b35, #ff9f28, #ffcc03);
|
||||
}
|
||||
}
|
||||
.uinput {
|
||||
width: 50% !important;
|
||||
> .sort-radius {
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
/deep/ .uni-input-input {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
.sort-radius {
|
||||
margin: 0 12rpx;
|
||||
background: #f7f7f7;
|
||||
height: 65rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 1000px;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
.flex {
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
> .sort-brand-item {
|
||||
width: 33%;
|
||||
text-align: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
.scoll-page {
|
||||
overflow: auto;
|
||||
}
|
||||
.content {
|
||||
background-color: $bg-color;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.index-nav-arrow:last-child {
|
||||
margin-top: -22rpx;
|
||||
}
|
||||
.line1-store-name {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
.to-store {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
.img {
|
||||
width: 26rpx;
|
||||
height: 26rpx;
|
||||
}
|
||||
.goods-row {
|
||||
background: #fff;
|
||||
padding: 16rpx;
|
||||
|
||||
> .goods-col {
|
||||
display: flex;
|
||||
> .goods-img {
|
||||
flex: 4;
|
||||
}
|
||||
> .goods-detail {
|
||||
flex: 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add1 {
|
||||
background: #fff;
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.oldKeyRow {
|
||||
background: #fff;
|
||||
padding: 34rpx 3%;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
}
|
||||
|
||||
.clamp3 {
|
||||
margin-bottom: 10rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
font-weight: 400;
|
||||
display: -webkit-box;
|
||||
height: 80rpx;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
-webkit-line-clamp: 2 !important;
|
||||
|
||||
overflow: hidden;
|
||||
> span {
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
view {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.store-seller-name {
|
||||
color: #666;
|
||||
overflow: hidden;
|
||||
|
||||
> div {
|
||||
float: left;
|
||||
}
|
||||
|
||||
> span {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.count-config {
|
||||
padding: 10rpx 0;
|
||||
color: #666;
|
||||
display: flex;
|
||||
font-size: 24rpx;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
z-index: 99;
|
||||
width: 100%;
|
||||
background: $light-color;
|
||||
padding: 20rpx 2.5%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.search-box .mSearch-input-box {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.search-box .input-box {
|
||||
width: 85%;
|
||||
flex-shrink: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.search-box .search-btn {
|
||||
width: 15%;
|
||||
margin: 0 0 0 2%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
font-size: 28rpx;
|
||||
color: #fff;
|
||||
background: linear-gradient(to right, #ff9801, #ff570a);
|
||||
border-radius: 60rpx;
|
||||
}
|
||||
|
||||
.search-box .input-box > input {
|
||||
width: 100%;
|
||||
height: 60rpx;
|
||||
font-size: 32rpx;
|
||||
border: 0;
|
||||
border-radius: 60rpx;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
padding: 0 3%;
|
||||
margin: 0;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.uni-scroll-view-content {
|
||||
background: #ededed !important;
|
||||
}
|
||||
|
||||
.placeholder-class {
|
||||
color: #9e9e9e;
|
||||
}
|
||||
|
||||
.search-keyword {
|
||||
width: 100%;
|
||||
background-color: #ededed;
|
||||
}
|
||||
|
||||
.keyword-list-box {
|
||||
height: calc(100vh - 110rpx);
|
||||
padding-top: 10rpx;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.keyword-entry-tap {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.keyword-entry {
|
||||
width: 94%;
|
||||
height: 80rpx;
|
||||
margin: 0 3%;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: solid 1rpx #e7e7e7;
|
||||
}
|
||||
|
||||
.keyword-entry image {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.keyword-entry .keyword-text,
|
||||
.keyword-entry .keyword-img {
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.keyword-entry .keyword-text {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.keyword-entry .keyword-img {
|
||||
width: 10%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.keyword-box {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.keyword-box .keyword-block {
|
||||
padding: 10rpx 0;
|
||||
}
|
||||
|
||||
.keyword-box .keyword-block .keyword-list-header {
|
||||
width: 100%;
|
||||
padding: 20rpx 3%;
|
||||
font-size: 27rpx;
|
||||
color: #333;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.keyword-box .keyword-block .keyword-list-header image {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.keyword-box .keyword-block .keyword > view {
|
||||
width: 50%;
|
||||
line-height: 1.75;
|
||||
overflow: hidden;
|
||||
padding: 0 3% 0 3% !important;
|
||||
}
|
||||
|
||||
.u-tips {
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.keyword {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.keyword-box {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.clear {
|
||||
color: #666666;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
font-size: 28rpx;
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.keyword-box .keyword-block .hide-hot-tis {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
color: #6b6b6b;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
background: #fff;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
|
||||
z-index: 10;
|
||||
// position: fixed;
|
||||
// left: 0;
|
||||
// top: var(--status-bar-height);
|
||||
.nav-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
font-size: 30rpx;
|
||||
color: $font-color-dark;
|
||||
position: relative;
|
||||
}
|
||||
.current {
|
||||
color: $light-color;
|
||||
position: relative;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 0;
|
||||
transform: translateX(-50%);
|
||||
width: 40rpx;
|
||||
height: 0;
|
||||
border-bottom: 4rpx solid $light-color;
|
||||
}
|
||||
}
|
||||
.p-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.yticon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 30rpx;
|
||||
height: 14rpx;
|
||||
line-height: 1;
|
||||
margin-left: 4rpx;
|
||||
font-size: 26rpx;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.xia {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
}
|
||||
|
||||
.cate-item {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 80rpx;
|
||||
position: relative;
|
||||
font-size: 44rpx;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
border-left: 1px solid #ddd;
|
||||
width: 0;
|
||||
height: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 分类 */
|
||||
.cate-mask {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: var(--window-top);
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: rgba(0, 0, 0, 0);
|
||||
z-index: 95;
|
||||
transition: 0.3s;
|
||||
|
||||
.cate-content {
|
||||
width: 630rpx;
|
||||
height: 100%;
|
||||
background: #fff;
|
||||
float: right;
|
||||
transform: translateX(100%);
|
||||
transition: 0.3s;
|
||||
}
|
||||
|
||||
&.none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.show {
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
|
||||
.cate-content {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cate-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.cate-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 90rpx;
|
||||
padding-left: 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #555;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.two {
|
||||
height: 64rpx;
|
||||
color: #303133;
|
||||
font-size: 30rpx;
|
||||
background: #f8f8f8;
|
||||
}
|
||||
}
|
||||
.price-box {
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: $font-color-light;
|
||||
}
|
||||
|
||||
.price {
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
/deep/ span:nth-of-type(1) {
|
||||
font-size: 38rpx;
|
||||
}
|
||||
}
|
||||
/* 商品列表 */
|
||||
.goods-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin: 10rpx 20rpx 0;
|
||||
|
||||
// background: #fff;
|
||||
width: 100%;
|
||||
.goods-item {
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
border-radius: 16rpx;
|
||||
flex-direction: column;
|
||||
width: calc(50% - 30rpx);
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
&:nth-child(2n + 1) {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.goods-detail {
|
||||
margin: 0 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
width: 100%;
|
||||
height: 330rpx;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 1;
|
||||
border-radius: 16rpx 16rpx 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: $font-base;
|
||||
color: $font-color-dark;
|
||||
line-height: 1.5;
|
||||
height: 84rpx;
|
||||
padding: 10rpx 0 0;
|
||||
display: -webkit-box;
|
||||
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
-webkit-line-clamp: 2;
|
||||
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.count-config,
|
||||
.store-seller-name {
|
||||
font-size: $font-sm;
|
||||
}
|
||||
|
||||
.text-hidden {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.status_bar {
|
||||
height: var(--status-bar-height);
|
||||
width: 100%;
|
||||
background: $light-color;
|
||||
}
|
||||
|
||||
.empty {
|
||||
padding-top: 300rpx;
|
||||
color: #999999;
|
||||
text-align: center;
|
||||
/deep/ .u-image {
|
||||
width: 346rpx;
|
||||
height: 304rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
288
pages/search/tuangou.vue
Normal file
288
pages/search/tuangou.vue
Normal file
@ -0,0 +1,288 @@
|
||||
<template>
|
||||
<view class="wrapper">
|
||||
<!-- 商品栏 -->
|
||||
<div class="swiper">
|
||||
<div v-if="groupBuy.length != 0">
|
||||
<view
|
||||
class="view-item"
|
||||
v-for="(groupItem, groupIndex) in groupBuy"
|
||||
:key="groupIndex"
|
||||
>
|
||||
<view class="view-left">
|
||||
<u-image
|
||||
border-radius="10"
|
||||
shape="square"
|
||||
:src="groupItem.thumbnail"
|
||||
width="186rpx"
|
||||
height="186rpx"
|
||||
>
|
||||
<view
|
||||
slot="error"
|
||||
style="font-size: 24rpx"
|
||||
>
|
||||
加载失败
|
||||
</view>
|
||||
</u-image>
|
||||
</view>
|
||||
<view class="view-content">
|
||||
<view class="view-content-name">
|
||||
{{ groupItem.goodsName }}
|
||||
</view>
|
||||
<view class="view-content-bottom">
|
||||
<view>
|
||||
<view class="view-content-price">
|
||||
<!-- ¥{{groupItem.sales_price | unitPrice }} <span v-if="groupItem.point">+{{groupItem.point}}积分</span> -->
|
||||
¥{{ groupItem.price | unitPrice }}
|
||||
</view>
|
||||
<view class="view-content-original_price">¥{{ groupItem.originalPrice | unitPrice }}</view>
|
||||
</view>
|
||||
|
||||
<view>
|
||||
<view
|
||||
class="btn-group"
|
||||
@click="toHref(groupItem)"
|
||||
>
|
||||
去拼团
|
||||
</view>
|
||||
<view class="buy-content">已售{{ groupItem.num || 0 }}件</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-loadmore
|
||||
style="padding: 10px 0"
|
||||
bg-color="#f8f8f8"
|
||||
:status="status"
|
||||
/>
|
||||
</div>
|
||||
<u-empty
|
||||
v-else
|
||||
style="margin-top: 20%"
|
||||
text="暂无数据"
|
||||
mode="data"
|
||||
></u-empty>
|
||||
</div>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as API_Promotions from '@/api/promotions';
|
||||
import * as API_Goods from '@/api/goods';
|
||||
export default {
|
||||
props: {
|
||||
keywords: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: 3, //tabs中的索引
|
||||
status: 'loadmore',
|
||||
is_empty: false,
|
||||
search: false,
|
||||
title: '拼团活动',
|
||||
background: {
|
||||
backgroundColor: '#fff'
|
||||
},
|
||||
empty: false,
|
||||
params: {
|
||||
pageNumber: 0,
|
||||
pageSize: 10,
|
||||
categoryPath: '',
|
||||
goodsName: ''
|
||||
},
|
||||
groupBuy: [],
|
||||
search: ''
|
||||
};
|
||||
},
|
||||
|
||||
created() {
|
||||
this.initData();
|
||||
},
|
||||
|
||||
methods: {
|
||||
initData() {
|
||||
this.search = this.keywords;
|
||||
this.status = 'loadmore';
|
||||
this.params = {
|
||||
pageNumber: 0,
|
||||
pageSize: 10,
|
||||
categoryPath: '',
|
||||
goodsName: this.search
|
||||
};
|
||||
this.groupBuy = [];
|
||||
console.log('初始化团购数据');
|
||||
this.getData();
|
||||
},
|
||||
|
||||
toHref(goods) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${goods.skuId}&goodsId=${goods.goodsId}`
|
||||
});
|
||||
},
|
||||
|
||||
// 请求拼团数据
|
||||
getData() {
|
||||
if (this.status !== 'loadmore') return;
|
||||
this.params.pageNumber++;
|
||||
this.status = 'loading';
|
||||
this.params.goodsName = this.search;
|
||||
const params = JSON.parse(JSON.stringify(this.params));
|
||||
if (params.category_id === 0) delete params.category_id;
|
||||
|
||||
API_Promotions.getAssembleList(params)
|
||||
.then((response) => {
|
||||
const data = response.data.result.records;
|
||||
|
||||
if (!data || !data.length) {
|
||||
this.is_empty = true;
|
||||
this.status = 'nomore';
|
||||
} else {
|
||||
if (data.length < this.params.pageSize) {
|
||||
this.status = 'nomore';
|
||||
} else {
|
||||
this.status = 'loadmore';
|
||||
}
|
||||
this.is_empty = false;
|
||||
this.groupBuy.push(...(data || []));
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.view-item {
|
||||
background: #fff;
|
||||
border-radius: 0.4em;
|
||||
margin: 20rpx 30rpx;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.nodata {
|
||||
text-align: center;
|
||||
margin: 40rpx 0 20rpx 0;
|
||||
}
|
||||
|
||||
.container-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
.white_class {
|
||||
color: #fff;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.popupTips {
|
||||
font-size: 22rpx;
|
||||
font-family: PingFang SC, PingFang SC-Regular;
|
||||
font-weight: 400;
|
||||
text-align: left;
|
||||
color: #999999;
|
||||
margin: 0 20rpx;
|
||||
|
||||
/deep/ view {
|
||||
line-height: 1.75;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
margin: 30rpx 20rpx !important;
|
||||
}
|
||||
|
||||
.view-left,
|
||||
.view-content,
|
||||
.view-right,
|
||||
.view-item {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.view-left {
|
||||
width: 226rpx;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.view-content {
|
||||
width: calc((100% - 240rpx));
|
||||
padding-left: 20rpx;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
.buy-content {
|
||||
font-size: 22rpx;
|
||||
font-family: PingFang SC, PingFang SC-Regular;
|
||||
font-weight: 400;
|
||||
margin-top: 15rpx;
|
||||
text-align: center;
|
||||
color: #999999;
|
||||
}
|
||||
.view-content-bottom {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.group-wrapper {
|
||||
padding: 16rpx 32rpx;
|
||||
}
|
||||
.view-content-name {
|
||||
font-family: PingFang SC, PingFang SC-Regular;
|
||||
font-weight: 400;
|
||||
text-align: left;
|
||||
color: #333333;
|
||||
font-size: 28rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
.view-content-price {
|
||||
margin: 10rpx 0;
|
||||
letter-spacing: 0px;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC, PingFang SC-Regular;
|
||||
font-weight: 400;
|
||||
text-align: left;
|
||||
color: #ff5a10;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.view-content-original_price {
|
||||
font-size: 22rpx;
|
||||
font-family: PingFang SC, PingFang SC-Regular;
|
||||
font-weight: 400;
|
||||
text-decoration: line-through;
|
||||
text-align: left;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
background: $aider-light-color;
|
||||
border-radius: 10rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC, PingFang SC-Regular;
|
||||
font-weight: 400;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 6rpx 16rpx;
|
||||
}
|
||||
/deep/ .empty {
|
||||
position: relative;
|
||||
padding-top: 20%;
|
||||
> .empty-content {
|
||||
position: relative;
|
||||
padding-top: 20%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
220
pages/search/user.vue
Normal file
220
pages/search/user.vue
Normal file
@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<view class="wrap">
|
||||
<view v-if="flowList.length">
|
||||
<view
|
||||
class="flex-box"
|
||||
v-for="i in flowList"
|
||||
v-if="i.id != id"
|
||||
:key="i.id"
|
||||
>
|
||||
<u-image
|
||||
:src="i.face"
|
||||
class="flxleft"
|
||||
width="120"
|
||||
height="120"
|
||||
shape="circle"
|
||||
loading-icon="/static/missing-face.png"
|
||||
error-icon="/static/missing-face.png"
|
||||
style="display: flex; align-items: center"
|
||||
></u-image>
|
||||
|
||||
<view class="flxcenter">
|
||||
<view class="nkname">{{ i.nickname }}</view>
|
||||
<!-- <view class="fans">粉丝:125.2万</view> -->
|
||||
</view>
|
||||
<view class="flxright">
|
||||
<u-button
|
||||
type="error"
|
||||
@click="follow(i)"
|
||||
size="mini"
|
||||
v-if="i.followStatus == '未关注'"
|
||||
>
|
||||
关注
|
||||
</u-button>
|
||||
<u-button
|
||||
v-else
|
||||
type="plain"
|
||||
@click="cancelFollow(i)"
|
||||
size="mini"
|
||||
>
|
||||
{{ i.followStatus }}
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
<u-loadmore
|
||||
style="padding: 10px 0"
|
||||
bg-color="#f8f8f8"
|
||||
:status="loadStatus"
|
||||
@loadmore="getData"
|
||||
></u-loadmore>
|
||||
</view>
|
||||
<u-empty
|
||||
v-else
|
||||
style="margin-top: 20%"
|
||||
text="暂无数据"
|
||||
mode="data"
|
||||
></u-empty>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import storage from '@/utils/storage.js'; //缓存
|
||||
import { vlogSearchUser, vlogFansFollow, vlogFansCancel } from '@/api/vlog';
|
||||
export default {
|
||||
props: {
|
||||
keywords: {
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
flag: 2, // 在tabs中的索引
|
||||
loadStatus: 'loadmore',
|
||||
flowList: [],
|
||||
page: 0,
|
||||
totalPage: 0,
|
||||
search: '',
|
||||
id: ''
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initData();
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
if (this.loadStatus !== 'loadmore') return;
|
||||
var info = storage.getVlogUserInfo();
|
||||
var id = '';
|
||||
if (info != null) {
|
||||
id = info.id;
|
||||
}
|
||||
this.id = id;
|
||||
this.loadStatus = 'loading';
|
||||
this.page += 1;
|
||||
console.log('加载用户数据');
|
||||
|
||||
var params = {
|
||||
id: id,
|
||||
nickname: this.search,
|
||||
page: this.page,
|
||||
pageSize: 10
|
||||
};
|
||||
console.log(params);
|
||||
var result = await vlogSearchUser(params);
|
||||
console.log(result);
|
||||
if (result.data.status == 200) {
|
||||
var data = result.data.data || [];
|
||||
if (!data.length) {
|
||||
this.loadStatus = 'nomore';
|
||||
} else {
|
||||
if (data.length < 10) {
|
||||
this.loadStatus = 'nomore';
|
||||
} else {
|
||||
this.loadStatus = 'loadmore';
|
||||
}
|
||||
data.forEach((i) => {
|
||||
i.doIflow = false;
|
||||
this.flowList.push(i);
|
||||
});
|
||||
// this.flowList.push(...data);
|
||||
}
|
||||
}
|
||||
},
|
||||
initData() {
|
||||
this.search = this.keywords;
|
||||
this.page = 0;
|
||||
this.totalPage = 0;
|
||||
this.flowList = [];
|
||||
this.loadStatus = 'loadmore';
|
||||
console.log('初始化用户数据');
|
||||
this.getData();
|
||||
},
|
||||
async follow(item) {
|
||||
let userInfo = storage.getVlogUserInfo();
|
||||
if (userInfo == null) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/passport/login',
|
||||
animationType: 'slide-in-bottom'
|
||||
});
|
||||
return;
|
||||
}
|
||||
let data = {
|
||||
myId: userInfo.id,
|
||||
vlogerId: item.id
|
||||
};
|
||||
var result = await vlogFansFollow(data);
|
||||
console.log(result);
|
||||
if (result.data.status == 200) {
|
||||
item.followStatus = '已关注';
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.data.msg,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
},
|
||||
async cancelFollow(item) {
|
||||
let userInfo = storage.getVlogUserInfo();
|
||||
if (userInfo == null) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/passport/login',
|
||||
animationType: 'slide-in-bottom'
|
||||
});
|
||||
return;
|
||||
}
|
||||
let data = {
|
||||
myId: userInfo.id,
|
||||
vlogerId: item.id
|
||||
};
|
||||
var result = await vlogFansCancel(data);
|
||||
console.log(result);
|
||||
if (result.data.status == 200) {
|
||||
item.doIflow = false;
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.data.msg,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flex-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 10rpx;
|
||||
padding: 10rpx 20rpx;
|
||||
}
|
||||
.flxleft {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.flxcenter {
|
||||
flex: 1;
|
||||
}
|
||||
.nkname {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 1;
|
||||
overflow: hidden;
|
||||
font-weight: 500;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
.fans {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
.flxright {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
@ -117,6 +117,11 @@ import SelectFriendqlioa from '@/TUIKit/components/TUIGroup/index.vue';
|
||||
import TUICore, { ExtensionInfo, TUIConstants } from '@tencentcloud/tui-core';
|
||||
import storage from '@/utils/storage.js';
|
||||
import { getUserimInfo, getMember, getMemberstate, getMemberdelete } from '@/api/members';
|
||||
|
||||
// push
|
||||
import { TUIConversationService } from '@tencentcloud/chat-uikit-engine';
|
||||
import * as Push from '@/uni_modules/TencentCloud-Push';
|
||||
|
||||
TUIChatKit.init();
|
||||
let vueVersion = 2;
|
||||
// vueVersion = 3;
|
||||
@ -161,8 +166,53 @@ export default {
|
||||
SDKAppID: par.sdkAppId,
|
||||
userID: par.userID,
|
||||
userSig: par.userSig,
|
||||
useUploadPlugin: true, // If you need to send rich media messages, please set to true.
|
||||
framework: `vue${vueVersion}` // framework used vue2 / vue3
|
||||
useUploadPlugin: true,
|
||||
framework: `vue${vueVersion}`
|
||||
}).then(() => {
|
||||
Push.setRegistrationID(par.userID, () => {
|
||||
console.log('设置id设置id设置id设置id设置id设置id设置id设置id设置id设置id', par.userID);
|
||||
|
||||
Push.registerPush(
|
||||
par.sdkAppId,
|
||||
'vkFpe55aYqfV7Sk5uGaoxhEstJ3tcI9dquk7JwG1GloDSLD2HeMWeQweWWXgNlhC',
|
||||
(data) => {
|
||||
console.log('registerPush ok', data);
|
||||
Push.getRegistrationID((registrationID) => {
|
||||
console.log('getRegistrationID ok', registrationID);
|
||||
});
|
||||
},
|
||||
(errCode, errMsg) => {
|
||||
console.error('registerPush failed', errCode, errMsg);
|
||||
}
|
||||
);
|
||||
});
|
||||
// 监听通知栏点击事件,获取推送扩展信息
|
||||
Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => {
|
||||
console.log('notification clicked', res);
|
||||
// 解析扩展信息,跳转到相应的会话(代码仅供参考,发布前需要完善)
|
||||
try {
|
||||
const data = JSON.parse(res.data);
|
||||
const conv_type = data?.entity?.chatType === 1 ? 'C2C' : 'GROUP';
|
||||
// 根据推送信息拼的 conversationID
|
||||
const conversationID = `${conv_type}${data.entity.sender}`;
|
||||
// 切换会话
|
||||
TUIConversationService.switchConversation(conversationID);
|
||||
const chatPath = '/TUIKit/components/TUIChat/index';
|
||||
uni.navigateTo({ url: chatPath });
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
}
|
||||
});
|
||||
// 监听在线推送
|
||||
Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => {
|
||||
// res 为消息内容
|
||||
console.log('message received', res);
|
||||
});
|
||||
// 监听在线推送被撤回
|
||||
Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => {
|
||||
// res 为被撤回的消息 ID
|
||||
console.log('message revoked', res);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 接口返回非 200 状态码,跳转登录页面
|
||||
|
||||
@ -229,7 +229,7 @@ export default {
|
||||
}, 300);
|
||||
},
|
||||
onTabItemTap: function (e) {
|
||||
console.log(e);
|
||||
// console.log(e);
|
||||
// let tabIndex = e.index;
|
||||
// this.playStatus = tabIndex === 0 ? true : false;
|
||||
// 切换视频要做暂停或播放的判断
|
||||
@ -343,7 +343,8 @@ export default {
|
||||
}
|
||||
});
|
||||
},
|
||||
fail: () => {
|
||||
fail: (err) => {
|
||||
console.log(err);
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '获取位置信息失败'
|
||||
@ -373,15 +374,7 @@ export default {
|
||||
let index = e.target.dataset.current || e.currentTarget.dataset.current;
|
||||
this.isTap = true;
|
||||
var currentSize = this.tabListSize[index];
|
||||
// if (obj.playerList.length === 0) {
|
||||
// this.isDraw_gz = false;
|
||||
// this.isDraw_lo = false;
|
||||
// this.isDraw_tj = false;
|
||||
// } else {
|
||||
// this.isDraw_gz = preloadIndex == 1 ? true : false;
|
||||
// this.isDraw_lo = preloadIndex == 0 ? true : false;
|
||||
// this.isDraw_tj = preloadIndex == 2 ? true : false;
|
||||
// }
|
||||
|
||||
this.updateIndicator(currentSize.left, currentSize.width);
|
||||
this._touchTabIndex = index;
|
||||
this.switchTab(index);
|
||||
@ -433,7 +426,6 @@ export default {
|
||||
this.isDraw_gz = false;
|
||||
this.isDraw_lo = false;
|
||||
this.isDraw_tj = false;
|
||||
console.log(this.playStatus);
|
||||
// if (this.playStatus == true) {
|
||||
// this.playStatus = this._lastTabIndex == 2 ? false : true;
|
||||
// }
|
||||
|
||||
29
uni_modules/TencentCloud-Push/changelog.md
Normal file
29
uni_modules/TencentCloud-Push/changelog.md
Normal file
@ -0,0 +1,29 @@
|
||||
## 1.2.0(2025-03-31)
|
||||
- 适配出海手机支持 FCM 推送。
|
||||
## 1.1.0(2024-12-11)
|
||||
- 大幅减小插件包体积,优化产品体验。
|
||||
- 兼容 HBuilderX 4.36 的 Breaking changes。如果您需要 vivo/荣耀 的厂商推送,请参考 [文档](https://cloud.tencent.com/document/product/269/103522),正确配置 `manifestPlaceholders.json` 和 `mcn-services.json`。
|
||||
|
||||
## 1.0.0(2024-11-29)
|
||||
- 优化和 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合时的产品体验。
|
||||
- 新增点击通知栏事件 NOTIFICATION_CLICKED,支持获取推送扩展信息。
|
||||
- 在线通道支持自定义铃音功能。
|
||||
|
||||
## 0.5.1(2024-11-07)
|
||||
- 优化和 [@tencentcloud/chat-uikit-uniapp](https://cloud.tencent.com/document/product/269/64507) 融合时的产品体验。
|
||||
- 优化和 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合时的产品体验。
|
||||
- 新增接口 disablePostNotificationInForeground,此接口可实现应用在前台时,开/关通知栏通知(默认开)。
|
||||
- 新增接口 createNotificationChannel,支持 FCM/OPPO 自定义铃音。
|
||||
|
||||
## 0.4.0(2024-10-17)
|
||||
- 支持与 [TencentCloud-TUICallKit 插件](https://ext.dcloud.net.cn/plugin?id=9035) 融合打包。
|
||||
|
||||
## 0.3.0(2024-10-12)
|
||||
- 新增接口 addPushListener/removePushListener,支持获取在线推送消息,支持推送消息撤回通知。
|
||||
|
||||
## 0.2.0(2024-09-18)
|
||||
- 支持 FCM
|
||||
- 支持 hihonor
|
||||
|
||||
## 0.1.0(2024-09-10)
|
||||
- 使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。
|
||||
0
uni_modules/TencentCloud-Push/index.js
Normal file
0
uni_modules/TencentCloud-Push/index.js
Normal file
90
uni_modules/TencentCloud-Push/package.json
Normal file
90
uni_modules/TencentCloud-Push/package.json
Normal file
@ -0,0 +1,90 @@
|
||||
{
|
||||
"name": "@tencentcloud/uni-app-push",
|
||||
"id": "TencentCloud-Push",
|
||||
"main": "index.js",
|
||||
"displayName": "【官方】uni-app 腾讯云推送服务(Push)",
|
||||
"version": "1.2.0",
|
||||
"description": "使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。",
|
||||
"license": "ISC",
|
||||
"keywords": [
|
||||
"腾讯云",
|
||||
"Push",
|
||||
"推送",
|
||||
"Android/iOS",
|
||||
"谷歌FCM"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.6.8"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "uts",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "腾讯云即时通信IM隐私保护指引: https://web.sdk.qcloud.com/document/Tencent-IM-Privacy-Protection-Guidelines.html\n移动推送隐私保护指引: https://privacy.qq.com/document/preview/8565a4a2d26e480187ed86b0cc81d727",
|
||||
"permissions": "本地存储空间"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-android": "y",
|
||||
"app-ios": "y",
|
||||
"app-harmony": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "u",
|
||||
"Android Browser": "u",
|
||||
"微信浏览器(Android)": "u",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
299
uni_modules/TencentCloud-Push/readme-npm.md
Normal file
299
uni_modules/TencentCloud-Push/readme-npm.md
Normal file
@ -0,0 +1,299 @@
|
||||
# TencentCloud-Push
|
||||
|
||||
## 简介
|
||||
|
||||
使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。
|
||||
|
||||
腾讯云推送服务(Push)提供一站式 App 推送解决方案,助您轻松提升用户留存和互动活跃度,支持与腾讯云即时通信 IM SDK、实时音视频 TRTC SDK、音视频通话 SDK、直播 SDK等音视频终端产品协同集成,在不同场景联合使用,提升业务整体功能体验。
|
||||
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/60d714484e54b284cfa440adcc885349.png" width="618" height="456">
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/864c391ecf6f2724d26e368e4f09e466.png" width="618" height="444">
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/6af60f4b20dd46323e8f901a161a80a9.png" width="618" height="454">
|
||||
|
||||
#### 数据可视化,辅助运营策略
|
||||
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/6c422f64900053c38a6bf66fe1103b3f.png" width="618" height="334">
|
||||
|
||||
#### 支持推送消息全链路问题排查
|
||||
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/156d43ed48971f9bf865ad0c4e2342e3.png" width="618" height="443">
|
||||
|
||||
#### 六地服务部署,严守数据安全
|
||||
|
||||
提供了中国、东南亚(新加坡、印尼雅加达)、东北亚(韩国首尔)、欧洲(德国法兰克福)以及北美(美国硅谷)数据存储中心供选择,每个数据中心均支持全球接入。如果您的应用在境外上线且用户主要在境外,您可以根据消息传输需求及合规要求,选择适合您业务的境外数据中心,保障您的数据安全。
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/2ffc1a103a42d9c01cfb819cd92bbd1d.png" widht="618" height="308">
|
||||
|
||||
## 快速跑通
|
||||
|
||||
### 步骤1:创建应用
|
||||
|
||||
进入 [控制台](https://console.cloud.tencent.com/im) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。
|
||||
|
||||

|
||||
|
||||
### 步骤2:开通推送服务 Push
|
||||
|
||||
进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天)
|
||||
|
||||

|
||||
|
||||
### 步骤3:下载腾讯云推送服务(Push)并复制 Push SDK 到您的项目中
|
||||
|
||||
1. 下载腾讯云推送服务(Push)。
|
||||
```
|
||||
npm install @tencentcloud/uni-app-push
|
||||
```
|
||||
|
||||
2. 复制 Push SDK 到您的项目中。
|
||||
|
||||
【macOS 端】
|
||||
|
||||
``` bash
|
||||
mkdir -p ./uni_modules/TencentCloud-Push && rsync -av ./node_modules/@tencentcloud/uni-app-push/ ./uni_modules/TencentCloud-Push
|
||||
```
|
||||
【Window 端】
|
||||
|
||||
``` bash
|
||||
xcopy .\node_modules\@tencentcloud\uni-app-push .\uni_modules\TencentCloud-Push /i /e
|
||||
```
|
||||
|
||||
### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push)
|
||||
|
||||
将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示:
|
||||
|
||||

|
||||
|
||||
```ts
|
||||
// 集成 TencentCloud-Push
|
||||
import * as Push from '@/uni_modules/TencentCloud-Push';
|
||||
const SDKAppID = 0; // 您的 SDKAppID
|
||||
const appKey = ''; // 客户端密钥
|
||||
Push.registerPush(SDKAppID, appKey, (data) => {
|
||||
console.log('registerPush ok', data);
|
||||
Push.getRegistrationID((registrationID) => {
|
||||
console.log('getRegistrationID ok', registrationID);
|
||||
});
|
||||
}, (errCode, errMsg) => {
|
||||
console.error('registerPush failed', errCode, errMsg);
|
||||
}
|
||||
);
|
||||
|
||||
// 监听通知栏点击事件,获取推送扩展信息
|
||||
Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => {
|
||||
// res 为推送扩展信息
|
||||
console.log('notification clicked', res);
|
||||
});
|
||||
|
||||
// 监听在线推送
|
||||
Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => {
|
||||
// res 为消息内容
|
||||
console.log('message received', res);
|
||||
});
|
||||
|
||||
// 监听在线推送被撤回
|
||||
Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => {
|
||||
// res 为被撤回的消息 ID
|
||||
console.log('message revoked', res);
|
||||
});
|
||||
```
|
||||
|
||||
### <span id="step5">步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)</span>
|
||||
|
||||
单击 HBuilderX 的 【运行 > 运行到手机或模拟器 > 制作自定义调试基座】,使用云端证书制作 Android 或 iOS 自定义调试基座。
|
||||
|
||||

|
||||
|
||||
自定义调试基座打好后,安装到手机运行。
|
||||
|
||||
[登录](https://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。
|
||||

|
||||
|
||||
## 厂商推送配置
|
||||
> - 请注意!HBuilderX 4.36 发布了不向下兼容的更新,如果您使用的是 HBuilderX 4.36 或者更高版本,且需要 vivo/荣耀 的厂商推送,
|
||||
请升级推送版本到 1.1.0 或更高版本,并参考文档正确配置 `manifestPlaceholders.json` 和 `mcs-services.json`。
|
||||
> - 请在 `nativeResources` 目录下进行推送配置。若项目根目录尚未创建该文件夹,请新建一个名为 `nativeResources` 的文件夹。
|
||||
> - 离线推送厂商配置完成后,需要打包自定义基座。参考:[[快速跑通]>[步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)]](#user-content-step5)
|
||||
|
||||
### 【Android】
|
||||
|
||||
1. 新建 nativeResources/android/assets 目录。
|
||||
|
||||
2. 在 [推送服务 Push > 接入设置 > 一键式快速配置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 下载 `timpush-configs.json` 文件,配置到 nativeResources/android/assets 目录下。
|
||||
|
||||
3. For 华为:
|
||||
|
||||
配置 `agconnect-services.json` (此文件获取详见 [厂商配置 > uniapp > 华为 > 步骤4:获取应用信息](https://cloud.tencent.com/document/product/269/103769))到 nativeResources/android 目录下。
|
||||
|
||||
4. For Google FCM:
|
||||
|
||||
4.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `project.plugins`,添加 `"com.google.gms.google-services"`,如下:
|
||||
```
|
||||
{
|
||||
...
|
||||
"project": {
|
||||
"plugins": [
|
||||
...
|
||||
"com.google.gms.google-services"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4.2. 配置 `google-services.json` 文件到 nativeResources/android/ 目录。
|
||||
|
||||
5. For 荣耀:
|
||||
|
||||
5.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:honor:8.3.6498"`,如下:
|
||||
```
|
||||
{
|
||||
...
|
||||
"dependencies": [
|
||||
...
|
||||
"com.tencent.timpush:honor:8.3.6498"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
5.2. 配置 `mcs-services.json` 文件到 nativeResources/android 目录下。
|
||||
|
||||
5.3. 配置 `appID` 到 nativeResources/android/manifestPlaceholders.json 中的 `"HONOR_APPID"`,如下:
|
||||
```
|
||||
{
|
||||
"HONOR_APPID": ""
|
||||
}
|
||||
```
|
||||
|
||||
6. For vivo:
|
||||
|
||||
6.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:vivo:8.3.6498"`,如下:
|
||||
```
|
||||
{
|
||||
...
|
||||
"dependencies": [
|
||||
...
|
||||
"com.tencent.timpush:vivo:8.3.6498"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
6.2. 配置 `appID` 和 `appKey` 到 nativeResources/android/manifestPlaceholders.json 中的 `VIVO_APPKEY` 和 `VIVO_APPID`,如下:
|
||||
```
|
||||
{
|
||||
"VIVO_APPKEY": "",
|
||||
"VIVO_APPID": "",
|
||||
}
|
||||
```
|
||||
|
||||
### 【iOS】
|
||||
|
||||
1. 新建 nativeResources/ios/Resources 目录。
|
||||
|
||||
2. 在 nativeResources/ios/Resources 中**新建 timpush-configs.json 文件**。
|
||||
|
||||
3. 并将在 [IM控制台 > 推送服务 Push > 接入设置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 获取的证书ID,补充到 timpush-configs.json 文件中。
|
||||
|
||||
```
|
||||
{
|
||||
"businessID":"xxx"
|
||||
}
|
||||
```
|
||||
|
||||
## 接口
|
||||
|
||||
| API | 描述|
|
||||
|----|---|
|
||||
| registerPush | 注册推送服务 (必须在 App 用户同意了隐私政策,并且允许为 App 用户提供推送服务后,再调用该接口使用推送服务)。<br>首次注册成功后,TencentCloud-Push SDK 生成该设备的标识 - RegistrationID。<br> 业务侧可以把这个 RegistrationID 保存到业务服务器。业务侧根据 RegistrationID 向设备推送消息或者通知。|
|
||||
| unRegisterPush | 反注册关闭推送服务。|
|
||||
| setRegistrationID | 设置注册推送服务使用的推送 ID 标识,即 RegistrationID。<br/>如果业务侧期望业务账号 ID 和推送 ID 一致,方便使用,可使用此接口,此时需注意,此接口需在 registerPush(注册推送服务)之前调用。|
|
||||
| getRegistrationID | 注册推送服务成功后,获取推送 ID 标识,即 RegistrationID。|
|
||||
| getNotificationExtInfo | 获取推送扩展信息。|
|
||||
| getNotificationExtInfo | 收到离线推送时,点击通知栏拉起 app,调用此接口可获取推送扩展信息。|
|
||||
| addPushListener | 添加 Push 监听器。|
|
||||
| removePushListener | 移除 Push 监听器。|
|
||||
| disablePostNotificationInForeground | 应用在前台时,开/关通知栏通知。|
|
||||
| createNotificationChannel | 创建客户端通知 channel。|
|
||||
|
||||
|
||||
```ts
|
||||
registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|SDKAppID|number|是|推送(Push)应用 ID|
|
||||
|appKey|string|是|推送(Push)应用客户端密钥|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|onError|function|否|接口调用失败的回调函数|
|
||||
|
||||
```ts
|
||||
unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|onError|function|否|接口调用失败的回调函数|
|
||||
|
||||
```ts
|
||||
setRegistrationID(registrationID: string, onSuccess: () => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|registrationID|string|是|设备的推送标识 ID,卸载重装会改变。|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|
||||
|
||||
```ts
|
||||
getRegistrationID(onSuccess: (registrationID: string) => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|
||||
```ts
|
||||
getNotificationExtInfo(onSuccess: (extInfo: string) => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|
||||
```ts
|
||||
addPushListener(eventName: string, listener: (data: any) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|eventName|string|是|推送事件类型|
|
||||
|listener|function|是|推送事件处理方法|
|
||||
|
||||
```ts
|
||||
removePushListener(eventName: string, listener?: (data: any) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|eventName|string|是|推送事件类型|
|
||||
|listener|function|否|推送事件处理方法|
|
||||
|
||||
```ts
|
||||
disablePostNotificationInForeground(disable: boolean);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|disable|boolean|是|应用在前台时,开/关通知栏通知,默认开<br/> - true: 应用在前台时,关闭通知栏通知。<br/> - false: 应用在前台时,开启通知栏通知。|
|
||||
|
||||
```ts
|
||||
createNotificationChannel(options: any, listener: (data: any) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|options.channelID|string|是|自定义 channel 的 ID|
|
||||
|options.channelName|string|是|自定义 channel 的名称|
|
||||
|options.channelDesc|string|否|自定义 channel 的描述|
|
||||
|options.channelSound|string|否|自定义 channel 的铃音,音频文件名,不带后缀,音频文件需要放到 xxx/nativeResources/android/res/raw 中。<br/> 例如:<br/> `options.channelSound = private_ring`,即设置 `xxx/nativeResources/android/res/raw/private_ring.mp3` 为自定义铃音|
|
||||
|listener|function|是|接口调用成功的回调函数|
|
||||
285
uni_modules/TencentCloud-Push/readme.md
Normal file
285
uni_modules/TencentCloud-Push/readme.md
Normal file
@ -0,0 +1,285 @@
|
||||
# TencentCloud-Push
|
||||
|
||||
## 简介
|
||||
|
||||
使用 uts 开发,基于腾讯云推送服务(Push),支持 iOS 和 Android 推送,同时适配各大厂商推送。
|
||||
|
||||
腾讯云推送服务(Push)提供一站式 App 推送解决方案,助您轻松提升用户留存和互动活跃度,支持与腾讯云即时通信 IM SDK、实时音视频 TRTC SDK、音视频通话 SDK、直播 SDK等音视频终端产品协同集成,在不同场景联合使用,提升业务整体功能体验。
|
||||
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/60d714484e54b284cfa440adcc885349.png" width="618" height="456">
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/864c391ecf6f2724d26e368e4f09e466.png" width="618" height="444">
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/6af60f4b20dd46323e8f901a161a80a9.png" width="618" height="454">
|
||||
|
||||
#### 数据可视化,辅助运营策略
|
||||
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/6c422f64900053c38a6bf66fe1103b3f.png" width="618" height="334">
|
||||
|
||||
#### 支持推送消息全链路问题排查
|
||||
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/156d43ed48971f9bf865ad0c4e2342e3.png" width="618" height="443">
|
||||
|
||||
#### 六地服务部署,严守数据安全
|
||||
|
||||
提供了中国、东南亚(新加坡、印尼雅加达)、东北亚(韩国首尔)、欧洲(德国法兰克福)以及北美(美国硅谷)数据存储中心供选择,每个数据中心均支持全球接入。如果您的应用在境外上线且用户主要在境外,您可以根据消息传输需求及合规要求,选择适合您业务的境外数据中心,保障您的数据安全。
|
||||
<img src="https://qcloudimg.tencent-cloud.cn/image/document/2ffc1a103a42d9c01cfb819cd92bbd1d.png" widht="618" height="308">
|
||||
|
||||
## 快速跑通
|
||||
|
||||
### 步骤1:创建应用
|
||||
|
||||
进入 [控制台](https://console.cloud.tencent.com/im) ,单击创建应用,填写应用名称,选择数据中心,单击确定,完成应用创建。
|
||||
|
||||

|
||||
|
||||
### 步骤2:开通推送服务 Push
|
||||
|
||||
进入 [推送服务 Push](https://console.cloud.tencent.com/im/push-plugin-push-identifier),单击立即购买或免费试用 。(每个应用可免费试用一次,有效期7天)
|
||||
|
||||

|
||||
|
||||
### 步骤3:将 [uni-app 腾讯云推送服务(Push)](https://ext.dcloud.net.cn/plugin?id=20169)插件导入 HbuilderX 中的工程。如图所示:
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
### 步骤4:在 App.vue 中引入并注册腾讯云推送服务(Push)
|
||||
|
||||
将 SDKAppID 和 appKey 替换为您在IM 控制台 - 推送服务 Push - 接入设置页面 获取的应用的信息。如图所示:
|
||||
|
||||

|
||||
|
||||
```ts
|
||||
// 集成 TencentCloud-Push
|
||||
import * as Push from '@/uni_modules/TencentCloud-Push';
|
||||
const SDKAppID = 0; // 您的 SDKAppID
|
||||
const appKey = ''; // 客户端密钥
|
||||
Push.registerPush(SDKAppID, appKey, (data) => {
|
||||
console.log('registerPush ok', data);
|
||||
Push.getRegistrationID((registrationID) => {
|
||||
console.log('getRegistrationID ok', registrationID);
|
||||
});
|
||||
}, (errCode, errMsg) => {
|
||||
console.error('registerPush failed', errCode, errMsg);
|
||||
}
|
||||
);
|
||||
|
||||
// 监听通知栏点击事件,获取推送扩展信息
|
||||
Push.addPushListener(Push.EVENT.NOTIFICATION_CLICKED, (res) => {
|
||||
// res 为推送扩展信息
|
||||
console.log('notification clicked', res);
|
||||
});
|
||||
|
||||
// 监听在线推送
|
||||
Push.addPushListener(Push.EVENT.MESSAGE_RECEIVED, (res) => {
|
||||
// res 为消息内容
|
||||
console.log('message received', res);
|
||||
});
|
||||
|
||||
// 监听在线推送被撤回
|
||||
Push.addPushListener(Push.EVENT.MESSAGE_REVOKED, (res) => {
|
||||
// res 为被撤回的消息 ID
|
||||
console.log('message revoked', res);
|
||||
});
|
||||
```
|
||||
|
||||
### <span id="step5">步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)</span>
|
||||
|
||||
单击 HBuilderX 的 【运行 > 运行到手机或模拟器 > 制作自定义调试基座】,使用云端证书制作 Android 或 iOS 自定义调试基座。
|
||||
|
||||

|
||||
|
||||
自定义调试基座打好后,安装到手机运行。
|
||||
|
||||
[登录](https://console.cloud.tencent.com/im/push-plugin-push-check) 控制台,使用测试工具进行在线推送测试。
|
||||

|
||||
|
||||
|
||||
## 厂商推送配置
|
||||
|
||||
> - 请注意!HBuilderX 4.36 发布了不向下兼容的更新,如果您使用的是 HBuilderX 4.36 或者更高版本,且需要 vivo/荣耀 的厂商推送,
|
||||
请升级推送版本到 1.1.0 或更高版本,并参考文档正确配置 `manifestPlaceholders.json` 和 `mcs-services.json`。
|
||||
> - 请在 `nativeResources` 目录下进行推送配置。若项目根目录尚未创建该文件夹,请新建一个名为 `nativeResources` 的文件夹。
|
||||
> - 厂商推送配置完成后,需要打包自定义基座。参考:[[快速跑通]>[步骤5:测试推送(测试前请务必打开手机通知权限,允许应用通知。)]](#step5)
|
||||
|
||||
#### 【Android】
|
||||
|
||||
1. 新建 nativeResources/android/assets 目录。
|
||||
|
||||
2. 在 [推送服务 Push > 接入设置 > 一键式快速配置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 下载 `timpush-configs.json` 文件,配置到 nativeResources/android/assets 目录下。
|
||||
|
||||
3. For 华为:
|
||||
|
||||
配置 `agconnect-services.json` (此文件获取详见 [厂商配置 > uniapp > 华为 > 步骤4:获取应用信息](https://cloud.tencent.com/document/product/269/103769))到 nativeResources/android 目录下。
|
||||
|
||||
4. For Google FCM:
|
||||
|
||||
4.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `project.plugins`,添加 `"com.google.gms.google-services"`,如下:
|
||||
```
|
||||
{
|
||||
...
|
||||
"project": {
|
||||
"plugins": [
|
||||
...
|
||||
"com.google.gms.google-services"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4.2. 配置 `google-services.json` 文件到 nativeResources/android/ 目录。
|
||||
|
||||
5. For 荣耀:
|
||||
|
||||
5.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:honor:8.3.6498"`,如下:
|
||||
```
|
||||
{
|
||||
...
|
||||
"dependencies": [
|
||||
...
|
||||
"com.tencent.timpush:honor:8.3.6498"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
5.2. 配置 `mcs-services.json` 文件到 nativeResources/android 目录下。
|
||||
|
||||
5.3. 配置 `appID` 到 nativeResources/android/manifestPlaceholders.json 中的 `"HONOR_APPID"`,如下:
|
||||
```
|
||||
{
|
||||
"HONOR_APPID": ""
|
||||
}
|
||||
```
|
||||
|
||||
6. For vivo:
|
||||
|
||||
6.1. 编辑 uni_modules/TencentCloud-Push/utssdk/app-android/config.json 的 `dependencies`,添加 `"com.tencent.timpush:vivo:8.3.6498"`,如下:
|
||||
```
|
||||
{
|
||||
...
|
||||
"dependencies": [
|
||||
...
|
||||
"com.tencent.timpush:vivo:8.3.6498"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
6.2. 配置 `appID` 和 `appKey` 到 nativeResources/android/manifestPlaceholders.json 中的 `VIVO_APPKEY` 和 `VIVO_APPID`,如下:
|
||||
```
|
||||
{
|
||||
"VIVO_APPKEY": "",
|
||||
"VIVO_APPID": "",
|
||||
}
|
||||
```
|
||||
|
||||
#### 【iOS】
|
||||
|
||||
1. 新建 nativeResources/ios/Resources 目录。
|
||||
|
||||
2. 在 nativeResources/ios/Resources 目录下新建 `timpush-configs.json` 文件。
|
||||
|
||||
3. 将在 [IM控制台 > 推送服务 Push > 接入设置](https://console.cloud.tencent.com/im/push-plugin-push-identifier) 获取的证书ID,补充到 `timpush-configs.json` 文件中。
|
||||
|
||||
```
|
||||
{
|
||||
"businessID":"xxx"
|
||||
}
|
||||
```
|
||||
|
||||
## 接口
|
||||
|
||||
| API | 描述|
|
||||
|----|---|
|
||||
| registerPush | 注册推送服务 (必须在 App 用户同意了隐私政策,并且允许为 App 用户提供推送服务后,再调用该接口使用推送服务)。<br>首次注册成功后,TencentCloud-Push SDK 生成该设备的标识 - RegistrationID。<br> 业务侧可以把这个 RegistrationID 保存到业务服务器。业务侧根据 RegistrationID 向设备推送消息或者通知。|
|
||||
| unRegisterPush | 反注册关闭推送服务。|
|
||||
| setRegistrationID | 设置注册推送服务使用的推送 ID 标识,即 RegistrationID。<br/>如果业务侧期望业务账号 ID 和推送 ID 一致,方便使用,可使用此接口,此时需注意,此接口需在 registerPush(注册推送服务)之前调用。|
|
||||
| getRegistrationID | 注册推送服务成功后,获取推送 ID 标识,即 RegistrationID。|
|
||||
| getNotificationExtInfo | 收到离线推送时,点击通知栏拉起 app,调用此接口可获取推送扩展信息。|
|
||||
| addPushListener | 添加 Push 监听器。|
|
||||
| removePushListener | 移除 Push 监听器。|
|
||||
| disablePostNotificationInForeground | 应用在前台时,开/关通知栏通知(默认开)。|
|
||||
| createNotificationChannel | 创建客户端通知 channel。|
|
||||
|
||||
```ts
|
||||
registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|SDKAppID|number|是|推送(Push)应用 ID|
|
||||
|appKey|string|是|推送(Push)应用客户端密钥|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|onError|function|否|接口调用失败的回调函数|
|
||||
|
||||
```ts
|
||||
unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|onError|function|否|接口调用失败的回调函数|
|
||||
|
||||
```ts
|
||||
setRegistrationID(registrationID: string, onSuccess: () => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|registrationID|string|是|设备的推送标识 ID,卸载重装会改变。|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|
||||
|
||||
```ts
|
||||
getRegistrationID(onSuccess: (registrationID: string) => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|
||||
```ts
|
||||
getNotificationExtInfo(onSuccess: (extInfo: string) => void): void;
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|onSuccess|function|是|接口调用成功的回调函数|
|
||||
|
||||
```ts
|
||||
addPushListener(eventName: string, listener: (data: any) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|eventName|string|是|推送事件类型|
|
||||
|listener|function|是|推送事件处理方法|
|
||||
|
||||
```ts
|
||||
removePushListener(eventName: string, listener?: (data: any) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|eventName|string|是|推送事件类型|
|
||||
|listener|function|否|推送事件处理方法|
|
||||
|
||||
```ts
|
||||
disablePostNotificationInForeground(disable: boolean);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|disable|boolean|是|应用在前台时,开/关通知栏通知,默认开<br/> - true: 应用在前台时,关闭通知栏通知。<br/> - false: 应用在前台时,开启通知栏通知。|
|
||||
|
||||
```ts
|
||||
createNotificationChannel(options: any, listener: (data: any) => void);
|
||||
```
|
||||
|
||||
|属性|类型|必填|说明|
|
||||
|----|---|----|----|
|
||||
|options.channelID|string|是|自定义 channel 的 ID|
|
||||
|options.channelName|string|是|自定义 channel 的名称|
|
||||
|options.channelDesc|string|否|自定义 channel 的描述|
|
||||
|options.channelSound|string|否|自定义 channel 的铃音,音频文件名,不带后缀,音频文件需要放到 xxx/nativeResources/android/res/raw 中。<br/> 例如:<br/> `options.channelSound = private_ring`,即设置 `xxx/nativeResources/android/res/raw/private_ring.mp3` 为自定义铃音|
|
||||
|listener|function|是|接口调用成功的回调函数|
|
||||
29
uni_modules/TencentCloud-Push/utssdk/app-android/config.json
Normal file
29
uni_modules/TencentCloud-Push/utssdk/app-android/config.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"minSdkVersion": "21",
|
||||
"dependencies": [
|
||||
"com.google.android.material:material:1.3.0",
|
||||
"com.google.code.gson:gson:2.9.1",
|
||||
"commons-codec:commons-codec:1.15",
|
||||
"com.github.bumptech.glide:glide:4.12.0",
|
||||
"com.tencent.timpush:timpush:8.5.6864",
|
||||
"com.tencent.liteav.tuikit:tuicore:8.5.6864",
|
||||
"com.tencent.timpush:huawei:8.5.6864",
|
||||
"com.tencent.timpush:xiaomi:8.5.6864",
|
||||
"com.tencent.timpush:oppo:8.5.6864",
|
||||
"com.tencent.timpush:meizu:8.5.6864",
|
||||
"com.tencent.timpush:fcm:8.5.6864",
|
||||
"com.tencent.timpush:honor:8.5.6864",
|
||||
"com.tencent.timpush:vivo:8.5.6864"
|
||||
],
|
||||
"project": {
|
||||
"plugins": [
|
||||
"com.huawei.agconnect",
|
||||
"com.hihonor.mcs.asplugin"
|
||||
],
|
||||
"dependencies": [
|
||||
"com.huawei.agconnect:agcp:1.9.1.301",
|
||||
"com.google.gms:google-services:4.3.15",
|
||||
"com.hihonor.mcs:asplugin:2.0.1.300"
|
||||
]
|
||||
}
|
||||
}
|
||||
152
uni_modules/TencentCloud-Push/utssdk/app-android/index.uts
Normal file
152
uni_modules/TencentCloud-Push/utssdk/app-android/index.uts
Normal file
@ -0,0 +1,152 @@
|
||||
import { UTSAndroid } from 'io.dcloud.uts';
|
||||
import Context from 'android.content.Context';
|
||||
import TIMPushManager from 'com.tencent.qcloud.tim.push.TIMPushManager';
|
||||
import TIMPushConfig from 'com.tencent.qcloud.tim.push.config.TIMPushConfig';
|
||||
import { PushCallbackOptions } from './push-callback-options.uts';
|
||||
import { PushListenerOptions } from './push-listener-options.uts';
|
||||
import PushCallback from './push-callback.uts';
|
||||
import PushListener from './push-listener.uts';
|
||||
|
||||
const context: Context | null = UTSAndroid.getAppContext();
|
||||
console.warn('Push | package.name:', context?.getPackageName());
|
||||
TIMPushConfig.getInstance().setRunningPlatform(2);
|
||||
const Push = TIMPushManager.getInstance();
|
||||
|
||||
export class EVENT {
|
||||
static MESSAGE_RECEIVED: string = 'message_received'
|
||||
static MESSAGE_REVOKED: string = 'message_revoked'
|
||||
static NOTIFICATION_CLICKED: string = 'notification_clicked'
|
||||
}
|
||||
|
||||
let disableNotification = false;
|
||||
export function disablePostNotificationInForeground(disable: boolean): void {
|
||||
console.log('Push | disablePostNotificationInForeground', disable);
|
||||
disableNotification = disable;
|
||||
Push.disablePostNotificationInForeground(disableNotification);
|
||||
}
|
||||
|
||||
export function registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void {
|
||||
if (SDKAppID == 0) {
|
||||
onError?.(9010001, 'Invalid SDKAppID');
|
||||
} else if (appKey == '') {
|
||||
onError?.(9010002, 'Invalid appKey');
|
||||
}
|
||||
const pushCbOptions: PushCallbackOptions = {
|
||||
apiName: 'registerPush',
|
||||
success: (res?: any) => {
|
||||
Push.disablePostNotificationInForeground(disableNotification);
|
||||
// 强转下类型,避免类型推断错误
|
||||
let token: string = res as string;
|
||||
onSuccess(token);
|
||||
},
|
||||
fail: (errCode: number, errMsg: string) => {
|
||||
onError?.(errCode, errMsg);
|
||||
}
|
||||
};
|
||||
// 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误
|
||||
Push.registerPush(context, SDKAppID.toInt(), appKey, new PushCallback(pushCbOptions));
|
||||
}
|
||||
|
||||
export function setRegistrationID(registrationID: string, onSuccess: () => void): void {
|
||||
const pushCbOptions: PushCallbackOptions = {
|
||||
apiName: 'setRegistrationID',
|
||||
success: (res?: any) => {
|
||||
onSuccess();
|
||||
},
|
||||
fail: (errCode: number, errMsg: string) => {
|
||||
// 空实现
|
||||
}
|
||||
};
|
||||
// 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误
|
||||
Push.setRegistrationID(registrationID, new PushCallback(pushCbOptions));
|
||||
}
|
||||
|
||||
export function getRegistrationID(onSuccess: (registrationID: string) => void): void {
|
||||
const pushCbOptions: PushCallbackOptions = {
|
||||
apiName: 'getRegistrationID',
|
||||
success: (res?: any) => {
|
||||
// 强转下类型,避免类型推断错误
|
||||
let registrationID: string = res as string;
|
||||
onSuccess(registrationID);
|
||||
},
|
||||
fail: (errCode: number, errMsg: string) => {
|
||||
// 空实现
|
||||
}
|
||||
};
|
||||
// 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误
|
||||
Push.getRegistrationID(new PushCallback(pushCbOptions));
|
||||
}
|
||||
|
||||
export function unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void {
|
||||
const pushCbOptions: PushCallbackOptions = {
|
||||
apiName: 'unRegisterPush',
|
||||
success: (res?: any) => {
|
||||
onSuccess();
|
||||
},
|
||||
fail: (errCode: number, errMsg: string) => {
|
||||
// 空实现
|
||||
},
|
||||
};
|
||||
// 注意!!! 这里不要写成 new PushCallback({ api, success, fail }),否则会因类型推断不一致导致编译错误
|
||||
Push.unRegisterPush(new PushCallback(pushCbOptions));
|
||||
}
|
||||
|
||||
export function createNotificationChannel(options: any, onSuccess: (extInfo: string) => void): void {
|
||||
const pushCbOptions: PushCallbackOptions = {
|
||||
apiName: 'createNotificationChannel',
|
||||
success: (res?: any) => {
|
||||
let ret: string = res as string;
|
||||
onSuccess(ret);
|
||||
},
|
||||
fail: (errCode: number, errMsg: string) => {
|
||||
// 空实现
|
||||
},
|
||||
};
|
||||
Push.callExperimentalAPI('createNotificationChannel', JSON.stringify(options), new PushCallback(pushCbOptions));
|
||||
}
|
||||
|
||||
export function getNotificationExtInfo(onSuccess: (extInfo: string) => void): void {
|
||||
const pushCbOptions: PushCallbackOptions = {
|
||||
apiName: 'getNotificationExtInfo',
|
||||
success: (res?: any) => {
|
||||
let ret: string = res as string;
|
||||
onSuccess(ret);
|
||||
},
|
||||
fail: (errCode: number, errMsg: string) => {
|
||||
// 空实现
|
||||
},
|
||||
};
|
||||
Push.callExperimentalAPI('getNotificationExtInfo', null, new PushCallback(pushCbOptions));
|
||||
}
|
||||
|
||||
const listenerMap = new Map<string, Array<(res: any) => void>>();
|
||||
|
||||
const pushListenerOptions: PushListenerOptions = {
|
||||
listener: (eventName: string, data: any) => {
|
||||
listenerMap.get(eventName)?.forEach(item => {
|
||||
item(data);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const pushListener = new PushListener(pushListenerOptions);
|
||||
|
||||
@UTSJS.keepAlive
|
||||
export function addPushListener(eventName: string, listener: (res: any) => void): void {
|
||||
if(listenerMap.size === 0) {
|
||||
Push.addPushListener(pushListener);
|
||||
}
|
||||
const listeners:Array<(res: any) => void> = [listener];
|
||||
listenerMap.get(eventName)?.forEach(item => {
|
||||
listeners.push(item);
|
||||
})
|
||||
listenerMap.set(eventName, listeners);
|
||||
}
|
||||
|
||||
|
||||
export function removePushListener(eventName: string, listener?: (res: any) => void): void {
|
||||
listenerMap.delete(eventName);
|
||||
if(listenerMap.size === 0) {
|
||||
Push.removePushListener(pushListener);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
export type PushCallbackOptions = {
|
||||
apiName: string
|
||||
success: (res?: any) => void
|
||||
fail: (errCode: number, errMsg: string) => void
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
import TIMPushCallback from 'com.tencent.qcloud.tim.push.TIMPushCallback';
|
||||
import { PushCallbackOptions } from './push-callback-options.uts';
|
||||
|
||||
const LOG_PREFIX: string = 'Push |';
|
||||
export default class PushCallback implements TIMPushCallback<any> {
|
||||
private apiName: string;
|
||||
private success: (data?: any) => void;
|
||||
private fail: (errCode: number, errMsg: string) => void;
|
||||
|
||||
constructor(options: PushCallbackOptions) {
|
||||
this.apiName = options.apiName;
|
||||
this.success = options.success;
|
||||
this.fail = options.fail;
|
||||
}
|
||||
|
||||
override onSuccess(data?: any) {
|
||||
console.log(`${LOG_PREFIX} ${this.apiName} ok, data:`, data);
|
||||
if (data == null) {
|
||||
this.success?.('');
|
||||
} else {
|
||||
this.success?.(data);
|
||||
}
|
||||
}
|
||||
|
||||
override onError(errCode: Int, errMsg: string, data?: any) {
|
||||
this.fail?.(errCode as number, errMsg);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
export type PushListenerOptions = {
|
||||
listener: (eventType: string, data: any) => void
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
import TIMPushListener from 'com.tencent.qcloud.tim.push.TIMPushListener';
|
||||
import TIMPushMessage from 'com.tencent.qcloud.tim.push.TIMPushMessage';
|
||||
import { PushListenerOptions } from './push-listener-options.uts';
|
||||
|
||||
const LOG_PREFIX: string = 'Push | PushListener';
|
||||
export default class PushListener implements TIMPushListener {
|
||||
private listener: (eventType: string, data: any) => void;
|
||||
|
||||
constructor(options: PushListenerOptions) {
|
||||
this.listener = options.listener;
|
||||
console.log(`${LOG_PREFIX} ok`);
|
||||
}
|
||||
|
||||
override onRecvPushMessage(message: TIMPushMessage) {
|
||||
this.listener('message_received', { data: message });
|
||||
}
|
||||
|
||||
override onRevokePushMessage(messageID: string) {
|
||||
this.listener('message_revoked', { data: messageID });
|
||||
}
|
||||
|
||||
override onNotificationClicked(ext: string) {
|
||||
this.listener('notification_clicked', { data: ext });
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>aps-environment</key>
|
||||
<string>development</string>
|
||||
</dict>
|
||||
</plist>
|
||||
11
uni_modules/TencentCloud-Push/utssdk/app-ios/config.json
Normal file
11
uni_modules/TencentCloud-Push/utssdk/app-ios/config.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"deploymentTarget": "9.0",
|
||||
"dependencies-pods": [
|
||||
{
|
||||
"name": "TXIMSDK_Plus_iOS_XCFramework",
|
||||
"version": "8.5.6864"
|
||||
}, {
|
||||
"name": "TIMPush",
|
||||
"version": "8.5.6864"
|
||||
}]
|
||||
}
|
||||
125
uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts
Normal file
125
uni_modules/TencentCloud-Push/utssdk/app-ios/index.uts
Normal file
@ -0,0 +1,125 @@
|
||||
import { TIMPushManager } from "TIMPush"
|
||||
import { NSObject } from "DCloudUTSFoundation"
|
||||
import PushListener from './push-listener.uts'
|
||||
import { PushListenerOptions } from './push-listener-options.uts'
|
||||
|
||||
const LOG_PREFIX = 'Push |';
|
||||
|
||||
export class EVENT {
|
||||
static MESSAGE_RECEIVED: string = 'message_received'
|
||||
static MESSAGE_REVOKED: string = 'message_revoked'
|
||||
static NOTIFICATION_CLICKED: string = 'notification_clicked'
|
||||
}
|
||||
|
||||
function setRunningPlatform(): void {
|
||||
console.log(LOG_PREFIX, 'setRunningPlatform');
|
||||
const param = new NSString("{\"runningPlatform\":2}");
|
||||
TIMPushManager.callExperimentalAPI('setPushConfig', param = param, succ = (ext?: NSObject): void => {
|
||||
let platform: string = ext as string;
|
||||
console.log(LOG_PREFIX, 'setRunningPlatform ok. platform:', platform);
|
||||
}, fail = (code?: Int32 ,desc?:String): void => {
|
||||
console.log(LOG_PREFIX, `setRunningPlatform fail. code: ${code}, desc: ${desc}`);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let disableNotification = false;
|
||||
|
||||
export function disablePostNotificationInForeground(_disable: boolean): void {
|
||||
console.log(LOG_PREFIX, 'disablePostNotificationInForeground', _disable);
|
||||
disableNotification = _disable;
|
||||
TIMPushManager.disablePostNotificationInForeground(disable = disableNotification);
|
||||
}
|
||||
|
||||
export function registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void {
|
||||
if (SDKAppID == 0) {
|
||||
onError?.(9010001, 'Invalid SDKAppID');
|
||||
} else if (appKey == '') {
|
||||
onError?.(9010002, 'Invalid appKey');
|
||||
}
|
||||
setRunningPlatform();
|
||||
TIMPushManager.registerPush(SDKAppID.toInt32(), appKey = appKey, succ = (deviceToken?: Data): void => {
|
||||
TIMPushManager.disablePostNotificationInForeground(disable = disableNotification);
|
||||
console.log('devicetoken ->', deviceToken, deviceToken?.count);
|
||||
onSuccess('');
|
||||
}, fail = (code?: Int32 ,desc?:String): void => {
|
||||
onError?.(code as number, desc as string);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function unRegisterPush(onSuccess: () => void, onError: (errCode: number, errMsg: string) => void): void {
|
||||
TIMPushManager.unRegisterPush((): void => {
|
||||
onSuccess();
|
||||
}, fail = (code?: Int32 ,desc?:String): void => {
|
||||
onError(code as number, desc as string);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function setRegistrationID(registrationID: string, onSuccess: () => void): void {
|
||||
console.log(LOG_PREFIX, 'setRegistrationID', `registrationID:${registrationID}`);
|
||||
TIMPushManager.setRegistrationID(registrationID, callback = (): void => {
|
||||
console.log(LOG_PREFIX, 'setRegistrationID ok');
|
||||
onSuccess();
|
||||
});
|
||||
}
|
||||
|
||||
export function getRegistrationID(onSuccess: (registrationID: string) => void): void {
|
||||
TIMPushManager.getRegistrationID((value ?: string): void => {
|
||||
// 这里需要转一下,否则会有问题
|
||||
let ret: string = value as string;
|
||||
onSuccess(ret);
|
||||
});
|
||||
}
|
||||
|
||||
export function createNotificationChannel(options: any, onSuccess: (data: string) => void): void {
|
||||
// 空实现
|
||||
}
|
||||
|
||||
// 注意!!!这里的 extInfo 不能写成 ext,否则会跟内部的 ext?:NSObject 有冲突;也不能写成 extension,否则会导致编译错误
|
||||
export function getNotificationExtInfo(onSuccess: (extInfo: string) => void): void {
|
||||
console.log(LOG_PREFIX, 'getNotificationExtInfo');
|
||||
TIMPushManager.callExperimentalAPI('getNotificationExtInfo', param = {}, succ = (ext?: NSObject): void => {
|
||||
let str: string = ext as string;
|
||||
console.log(LOG_PREFIX, 'getNotificationExtInfo ok. ext:', str);
|
||||
onSuccess(str);
|
||||
}, fail = (code?: Int32 ,desc?:String): void => {
|
||||
// 空实现
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const listenerMap = new Map<string, Array<(res: any) => void>>();
|
||||
|
||||
const pushListenerOptions: PushListenerOptions = {
|
||||
listener: (eventName: string, data: any) => {
|
||||
listenerMap.get(eventName)?.forEach(item => {
|
||||
item(data);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const pushListener = new PushListener(pushListenerOptions);
|
||||
|
||||
@UTSJS.keepAlive
|
||||
export function addPushListener(eventName: string, _listener: (res: any) => void): void {
|
||||
console.log(LOG_PREFIX, 'addPushListener', eventName);
|
||||
if(listenerMap.size === 0) {
|
||||
TIMPushManager.addPushListener(listener = pushListener);
|
||||
}
|
||||
const listeners:Array<(res: any) => void> = [_listener];
|
||||
listenerMap.get(eventName)?.forEach(item => {
|
||||
listeners.push(item);
|
||||
})
|
||||
listenerMap.set(eventName, listeners);
|
||||
}
|
||||
|
||||
export function removePushListener(eventName: string, _listener?: (res: any) => void): void {
|
||||
console.log(LOG_PREFIX, 'removePushListener', eventName);
|
||||
listenerMap.delete(eventName);
|
||||
if(listenerMap.size === 0) {
|
||||
TIMPushManager.removePushListener(listener = pushListener);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
export type PushListenerOptions = {
|
||||
listener: (eventType: string, data: any) => void
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
import { TIMPushListener, TIMPushMessage} from "TIMPush"
|
||||
import { PushListenerOptions } from './push-listener-options.uts';
|
||||
|
||||
const LOG_PREFIX: string = 'Push | PushListener';
|
||||
export default class PushListener implements TIMPushListener {
|
||||
private listener: (eventType: string, data: any) => void;
|
||||
|
||||
constructor(options: PushListenerOptions) {
|
||||
this.listener = options.listener;
|
||||
console.log(`${LOG_PREFIX} ok`);
|
||||
}
|
||||
|
||||
onRecvPushMessage(message: TIMPushMessage) {
|
||||
this.listener('message_received', { data: message });
|
||||
}
|
||||
|
||||
onRevokePushMessage(messageID: string) {
|
||||
this.listener('message_revoked', { data: messageID });
|
||||
}
|
||||
|
||||
onNotificationClicked(ext: string) {
|
||||
this.listener('notification_clicked', { data: ext });
|
||||
}
|
||||
}
|
||||
11
uni_modules/TencentCloud-Push/utssdk/interface.uts
Normal file
11
uni_modules/TencentCloud-Push/utssdk/interface.uts
Normal file
@ -0,0 +1,11 @@
|
||||
interface Push {
|
||||
setRegistrationID(registrationID: string, onSuccess: () => void): void,
|
||||
registerPush(SDKAppID: number, appKey: string, onSuccess: (data: string) => void, onError?: (errCode: number, errMsg: string) => void): void,
|
||||
getRegistrationID(onSuccess: (registrationID: string) => void): void,
|
||||
unRegisterPush(onSuccess: () => void, onError?: (errCode: number, errMsg: string) => void): void,
|
||||
getNotificationExtInfo(onSuccess: (extInfo: string) => void): void
|
||||
addPushListener(eventName: string, listener: (res: any) => void): void
|
||||
removePushListener(eventName: string, listener?: (res: any) => void): void
|
||||
disablePostNotificationInForeground(disable: boolean): void
|
||||
createNotificationChannel(options: any, onSuccess: (data: string) => void): void
|
||||
}
|
||||
@ -26,13 +26,13 @@ function cleanStorage() {
|
||||
storage.setRefreshToken("");
|
||||
console.log("清空token");
|
||||
storage.setUuid("");
|
||||
storage.setUserInfo({});
|
||||
// 清理vlog信息
|
||||
storage.setVlogToken("")
|
||||
storage.setVlogUserInfo({})
|
||||
// 清除初始化数据内容
|
||||
storage.setUserInfo({});
|
||||
// 清理vlog信息
|
||||
storage.setVlogToken("")
|
||||
storage.setVlogUserInfo(null)
|
||||
// 清除初始化数据内容
|
||||
storage.setRefreshVlogIndex('0') //不需要刷新
|
||||
|
||||
|
||||
// 防抖处理跳转
|
||||
// #ifdef MP-WEIXIN
|
||||
|
||||
@ -96,23 +96,23 @@ http.interceptors.request.use(
|
||||
config.header.accessToken = accessToken;
|
||||
|
||||
}
|
||||
// 配置vlog所需参数
|
||||
let vlogToken = storage.getVlogToken();
|
||||
let vlogId = storage.getVlogUserInfo();
|
||||
// console.log(vlogId)
|
||||
// console.log(vlogToken)
|
||||
if(vlogToken){
|
||||
config.header.headerUserToken = vlogToken;
|
||||
config.header.headerUserId = vlogId.id;
|
||||
// 配置vlog所需参数
|
||||
let vlogToken = storage.getVlogToken();
|
||||
let vlogId = storage.getVlogUserInfo();
|
||||
// console.log(vlogId)
|
||||
// console.log(vlogToken)
|
||||
if (vlogToken) {
|
||||
config.header.headerUserToken = vlogToken;
|
||||
config.header.headerUserId = vlogId.id;
|
||||
}
|
||||
config.header = {
|
||||
...config.header,
|
||||
uuid: storage.getUuid() || uuid.v1(),
|
||||
};
|
||||
};
|
||||
// console.log(config)
|
||||
return config;
|
||||
},
|
||||
(config) => {
|
||||
(config) => {
|
||||
return Promise.reject(config);
|
||||
}
|
||||
);
|
||||
@ -124,8 +124,8 @@ let isRefreshing = false;
|
||||
let requests = [];
|
||||
// 必须使用异步函数,注意
|
||||
http.interceptors.response.use(
|
||||
async (response) => {
|
||||
// console.log(isRefreshing)
|
||||
async (response) => {
|
||||
// console.log(isRefreshing)
|
||||
// console.log(response)
|
||||
/* 请求之后拦截器。可以使用async await 做异步操作 */
|
||||
// token存在并且token过期
|
||||
@ -194,9 +194,8 @@ http.interceptors.response.use(
|
||||
duration: 1500,
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (response.data.code==502){
|
||||
cleanStorage();
|
||||
} else if (response.data.code == 502) {
|
||||
cleanStorage();
|
||||
}
|
||||
return response;
|
||||
},
|
||||
|
||||
@ -95,16 +95,28 @@ const theNextDayTime = () => {
|
||||
};
|
||||
|
||||
const graceNumber = (number) => {
|
||||
// if (number == 0) {
|
||||
// return "0";
|
||||
// } else if (number > 999 && number <= 9999) {
|
||||
// return (number / 1000).toFixed(1) + "k";
|
||||
// } else if (number > 9999 && number <= 99999) {
|
||||
// return (number / 10000).toFixed(1) + "w";
|
||||
// } else if (number > 99999) {
|
||||
// return "10w+";
|
||||
// }
|
||||
// return number;
|
||||
if (number == 0) {
|
||||
return "0";
|
||||
} else if (number > 999 && number <= 9999) {
|
||||
return (number / 1000).toFixed(1) + "k";
|
||||
} else if (number > 9999 && number <= 99999) {
|
||||
return (number / 10000).toFixed(1) + "w";
|
||||
} else if (number > 99999) {
|
||||
return "10w+";
|
||||
}
|
||||
return number;
|
||||
if (number < 1000) {
|
||||
return number.toString();
|
||||
} else if (number < 10000) {
|
||||
return (number / 1000).toFixed(1).replace(/\.0$/, '') + "k";
|
||||
} else if (number < 100000000) {
|
||||
return (number / 10000).toFixed(1).replace(/\.0$/, '') + "w";
|
||||
} else {
|
||||
return (number / 100000000).toFixed(1).replace(/\.0$/, '') + "亿+";
|
||||
}
|
||||
}
|
||||
|
||||
// 时间格式化时间为: 多少分钟前、多少天前
|
||||
@ -237,6 +249,6 @@ export {
|
||||
getDateBeforeNow,
|
||||
isStrEmpty,
|
||||
getAstro,
|
||||
getAnimal,
|
||||
getAnimal,
|
||||
dateFormat
|
||||
};
|
||||
@ -1,35 +1,35 @@
|
||||
// const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default;
|
||||
|
||||
module.exports = {
|
||||
parallel: false,
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
// ScriptSetup({
|
||||
// /* options */
|
||||
// }),
|
||||
],
|
||||
},
|
||||
chainWebpack(config) {
|
||||
// disable type check and let `vue-tsc` handles it
|
||||
config.plugins.delete('fork-ts-checker');
|
||||
},
|
||||
};
|
||||
// module.exports = {
|
||||
// /**
|
||||
// * 此处为发行h5,微信小程序,app中删除console
|
||||
// * 如需显示console 需要注释此处重新运行
|
||||
// */
|
||||
// chainWebpack: (config) => {
|
||||
// // 发行或运行时启用了压缩时会生效
|
||||
// config.optimization.minimizer('terser').tap((args) => {
|
||||
// const compress = args[0].terserOptions.compress
|
||||
// // 非 App 平台移除 console 代码(包含所有 console 方法,如 log,debug,info...)
|
||||
// compress.drop_console = true
|
||||
// compress.pure_funcs = [
|
||||
// '__f__', // App 平台 vue 移除日志代码
|
||||
// // 'console.debug' // 可移除指定的 console 方法
|
||||
// ]
|
||||
// return args
|
||||
// })
|
||||
// }
|
||||
const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default;
|
||||
|
||||
module.exports = {
|
||||
parallel: false,
|
||||
configureWebpack: {
|
||||
plugins: [
|
||||
ScriptSetup({
|
||||
/* options */
|
||||
}),
|
||||
],
|
||||
},
|
||||
chainWebpack(config) {
|
||||
// disable type check and let `vue-tsc` handles it
|
||||
config.plugins.delete('fork-ts-checker');
|
||||
},
|
||||
};
|
||||
// module.exports = {
|
||||
// /**
|
||||
// * 此处为发行h5,微信小程序,app中删除console
|
||||
// * 如需显示console 需要注释此处重新运行
|
||||
// */
|
||||
// chainWebpack: (config) => {
|
||||
// // 发行或运行时启用了压缩时会生效
|
||||
// config.optimization.minimizer('terser').tap((args) => {
|
||||
// const compress = args[0].terserOptions.compress
|
||||
// // 非 App 平台移除 console 代码(包含所有 console 方法,如 log,debug,info...)
|
||||
// compress.drop_console = true
|
||||
// compress.pure_funcs = [
|
||||
// '__f__', // App 平台 vue 移除日志代码
|
||||
// // 'console.debug' // 可移除指定的 console 方法
|
||||
// ]
|
||||
// return args
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
Loading…
x
Reference in New Issue
Block a user