This commit is contained in:
陈浩 2025-04-21 18:04:01 +08:00
commit f1d1f5cc5c
122 changed files with 14926 additions and 6520 deletions

543
App.vue
View File

@ -1,273 +1,270 @@
<script> <script>
/** /**
* vuex管理登录状态具体可以参考官方登录模板示例 * vuex管理登录状态具体可以参考官方登录模板示例
*/ */
import { mapMutations } from "vuex"; import { mapMutations } from 'vuex';
import APPUpdate from "@/plugins/APPUpdate"; import APPUpdate from '@/plugins/APPUpdate';
import { getClipboardData } from "@/js_sdk/h5-copy/h5-copy.js"; import { getClipboardData } from '@/js_sdk/h5-copy/h5-copy.js';
import config from "@/config/config"; import config from '@/config/config';
// code // code
import provinceList from "./json/area_province.js"; import provinceList from './json/area_province.js';
import cityList from "./json/area_city.js"; import cityList from './json/area_city.js';
import districtList from "./json/area_district.js"; import districtList from './json/area_district.js';
import storage from "@/utils/storage.js"; // import storage from '@/utils/storage.js'; //
export default {
data() { export default {
return { data() {
config, return {
}; config
}, };
},
/**
* 监听返回 /**
*/ * 监听返回
onBackPress(e) { */
if (e.from == "backbutton") { onBackPress(e) {
let routes = getCurrentPages(); if (e.from == 'backbutton') {
let curRoute = routes[routes.length - 1].options; let routes = getCurrentPages();
routes.forEach((item) => { let curRoute = routes[routes.length - 1].options;
if ( routes.forEach((item) => {
item.route == "pages/tabbar/cart/cartList" || if (item.route == 'pages/tabbar/cart/cartList' || item.route.indexOf('pages/product/goods') != -1) {
item.route.indexOf("pages/product/goods") != -1 uni.redirectTo({
) { url: item.route
uni.redirectTo({ });
url: item.route, }
}); });
}
}); if (curRoute.addId) {
uni.reLaunch({
if (curRoute.addId) { url: '/pages/tabbar/cart/cartList'
uni.reLaunch({ });
url: "/pages/tabbar/cart/cartList", } else {
}); uni.navigateBack();
} else { }
uni.navigateBack(); return true; //
} }
return true; // },
} methods: {
}, ...mapMutations(['login'])
methods: { },
...mapMutations(["login"]), onLaunch: function () {
}, // #ifdef APP-PLUS
onLaunch: function () { this.checkArguments(); //
// #ifdef APP-PLUS APPUpdate();
this.checkArguments(); // this.hanleTabCenter();
APPUpdate(); //
this.hanleTabCenter(); plus.globalEvent.addEventListener('newintent', (e) => {
// this.checkArguments(); //
plus.globalEvent.addEventListener("newintent", (e) => { });
this.checkArguments(); // // #endif
});
// #endif // #ifdef MP-WEIXIN
this.applyUpdateWeChat();
// #ifdef MP-WEIXIN // #endif
this.applyUpdateWeChat(); },
// #endif
}, onShow() {
// #ifndef H5
onShow() { this.getClipboard();
// #ifndef H5 // #endif
this.getClipboard(); },
// #endif methods: {
}, //
methods: { hanleTabCenter() {
// //
hanleTabCenter() { uni.onTabBarMidButtonTap(() => {
// console.log('center');
uni.onTabBarMidButtonTap(() => { //
console.log("center"); let myUserInfo = storage.getVlogUserInfo();
// if (myUserInfo == null) {
let myUserInfo = storage.getVlogUserInfo() || null; uni.navigateTo({
if (myUserInfo == null) { // url: "../loginRegist/loginRegist",
uni.navigateTo({ url: '/pages/passport/login',
// url: "../loginRegist/loginRegist", animationType: 'slide-in-bottom',
url: "/pages/passport/login", success() {
animationType: "slide-in-bottom", this.loginWords = '请登录';
success() { }
this.loginWords = "请登录"; });
}, return;
}); }
return;
} uni.chooseVideo({
sourceType: ['album'],
uni.chooseVideo({ compressed: false,
sourceType: ["album"], success(e) {
compressed: false, console.log(JSON.stringify(e));
success(e) { uni.navigateTo({
console.log(JSON.stringify(e)); url: '/pages/publish/publish?fileObjectEvent=' + JSON.stringify(e)
uni.navigateTo({ });
url: }
"/pages/publish/publish?fileObjectEvent=" + JSON.stringify(e), });
}); });
}, },
}); /**
}); * 微信小程序版本提交更新版本 解决缓存问题
}, */
/** applyUpdateWeChat() {
* 微信小程序版本提交更新版本 解决缓存问题 const updateManager = uni.getUpdateManager();
*/
applyUpdateWeChat() { updateManager.onCheckForUpdate(function (res) {
const updateManager = uni.getUpdateManager(); //
});
updateManager.onCheckForUpdate(function (res) {
// updateManager.onUpdateReady(function (res) {
}); uni.showModal({
title: '更新提示',
updateManager.onUpdateReady(function (res) { content: '发现新版本,是否重启应用?',
uni.showModal({ success(res) {
title: "更新提示", if (res.confirm) {
content: "发现新版本,是否重启应用?", // applyUpdate
success(res) { updateManager.applyUpdate();
if (res.confirm) { }
// applyUpdate }
updateManager.applyUpdate(); });
} });
}, updateManager.onUpdateFailed(function (res) {
}); //
}); });
updateManager.onUpdateFailed(function (res) { },
//
}); // TODO 广
}, launch() {
try {
// TODO 广 // launchFlag 广
launch() { const value = uni.getStorageSync('launchFlag');
try { if (!value) {
// launchFlag 广 // this.$u.route("/pages/index/agreement");
const value = uni.getStorageSync("launchFlag"); } else {
if (!value) { //app广
// this.$u.route("/pages/index/agreement"); var w = plus.webview.open(
} else { '/hybrid/html/advertise/advertise.html',
//app广 '本地地址',
var w = plus.webview.open( {
"/hybrid/html/advertise/advertise.html", top: 0,
"本地地址", bottom: 0,
{ zindex: 999
top: 0, },
bottom: 0, 'fade-in',
zindex: 999, 500
}, );
"fade-in", //4s广
500 setTimeout(function () {
); plus.webview.close(w);
//4s广 APPUpdate();
setTimeout(function () { }, 3000);
plus.webview.close(w); }
APPUpdate(); } catch (e) {
}, 3000); // error
} uni.setStorage({
} catch (e) { key: 'launchFlag',
// error data: true,
uni.setStorage({ success: function () {
key: "launchFlag", console.log('error时存储launchFlag');
data: true, }
success: function () { });
console.log("error时存储launchFlag"); }
}, },
});
} /**
}, * 获取粘贴板数据
*/
/** async getClipboard() {
* 获取粘贴板数据 let res = await getClipboardData();
*/ /**
async getClipboard() { * 解析粘贴板数据
let res = await getClipboardData(); */
/** if (res.indexOf(config.shareLink) != -1) {
* 解析粘贴板数据 uni.showModal({
*/ title: '提示',
if (res.indexOf(config.shareLink) != -1) { content: '检测到一个分享链接是否跳转?',
uni.showModal({ confirmText: '跳转',
title: "提示", success: function (callback) {
content: "检测到一个分享链接是否跳转?", if (callback.confirm) {
confirmText: "跳转", const path = res.split(config.shareLink)[1];
success: function (callback) { if (path.indexOf('tabbar') != -1) {
if (callback.confirm) { uni.switchTab({
const path = res.split(config.shareLink)[1]; url: path
if (path.indexOf("tabbar") != -1) { });
uni.switchTab({ } else {
url: path, uni.navigateTo({
}); url: path
} else { });
uni.navigateTo({ }
url: path, }
}); }
} });
} }
}, },
});
} /**
}, * h5中打开app获取跳转app的链接并跳转
*/
/** checkArguments() {
* h5中打开app获取跳转app的链接并跳转 // #ifdef APP-PLUS
*/ setTimeout(() => {
checkArguments() { const args = plus.runtime.arguments;
// #ifdef APP-PLUS if (args) {
setTimeout(() => { const argsStr = decodeURIComponent(args);
const args = plus.runtime.arguments; const path = argsStr.split('//')[1];
if (args) { if (path.indexOf('tabbar') != -1) {
const argsStr = decodeURIComponent(args); uni.switchTab({
const path = argsStr.split("//")[1]; url: `/${path}`
if (path.indexOf("tabbar") != -1) { });
uni.switchTab({ } else {
url: `/${path}`, uni.navigateTo({
}); url: `/${path}`
} else { });
uni.navigateTo({ }
url: `/${path}`, }
}); });
} // #endif
} }
}); }
// #endif };
}, </script>
},
}; <style lang="scss">
</script> /* #ifndef APP-NVUE */
@import 'uview-ui/index.scss';
<style lang="scss"> /* #endif */
/* #ifndef APP-NVUE */
@import "uview-ui/index.scss"; // ------- x
/* #endif */
// #ifdef MP-WEIXIN
// ------- x .mp-iphonex-bottom {
padding-bottom: constant(safe-area-inset-bottom);
// #ifdef MP-WEIXIN padding-bottom: env(safe-area-inset-bottom);
.mp-iphonex-bottom { box-sizing: content-box;
padding-bottom: constant(safe-area-inset-bottom); height: auto !important;
padding-bottom: env(safe-area-inset-bottom); padding-top: 10rpx;
box-sizing: content-box; }
height: auto !important; // #endif
padding-top: 10rpx;
} /* #ifndef APP-NVUE */
// #endif body {
background-color: $bg-color;
/* #ifndef APP-NVUE */ }
body { /* #endif */
background-color: $bg-color;
} /************************ */
/* #endif */ .w200 {
width: 200rpx !important;
/************************ */ }
.w200 {
width: 200rpx !important; .flex1 {
} flex: 1; //flex
}
.flex1 { .activate-line {
flex: 1; //flex background-color: #ffffff;
}
.activate-line { transition-duration: 300ms;
background-color: #ffffff; }
// uni-page-body,
transition-duration: 300ms; // html,
} // body,
// uni-page-body, // page {
// html, // width: 100% ;
// body, // height: 100% ;
// page { // overflow: hidden;
// width: 100% ; // }
// height: 100% ; </style>
// overflow: hidden;
// }
</style>

View File

@ -1,60 +1,60 @@
body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p { body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p {
margin:0; margin:0;
padding:0; padding:0;
font-style:normal; font-style:normal;
/* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */ /* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */
} }
ol, ul, li { ol, ul, li {
list-style:none; list-style:none;
} }
img { img {
border:0; border:0;
vertical-align:middle; vertical-align:middle;
pointer-events:none; pointer-events:none;
} }
body{ body{
height: 100% important; height: 100% important;
color:#000; color:#000;
background:#FFF; background:#FFF;
} }
.clear { .clear {
clear:both; clear:both;
height:1px; height:1px;
width:100%; width:100%;
overflow:hidden; overflow:hidden;
margin-top:-1px; margin-top:-1px;
} }
a { a {
color:#000; color:#000;
text-decoration:none; text-decoration:none;
cursor: pointer; cursor: pointer;
} }
a:hover { a:hover {
text-decoration:none; text-decoration:none;
} }
input, textarea { input, textarea {
user-select: auto; user-select: auto;
} }
input:focus, input:active, textarea:focus, textarea:active { input:focus, input:active, textarea:focus, textarea:active {
outline: none; outline: none;
} }
.chat-aside { .chat-aside {
position: absolute; position: absolute;
top: 50px; top: 50px;
right: 0; right: 0;
box-sizing: border-box; box-sizing: border-box;
width: 360px !important; width: 360px !important;
border-radius: 8px 0 0 8px; border-radius: 8px 0 0 8px;
z-index: 9999; z-index: 9999;
max-height: calc(100% - 50px); max-height: calc(100% - 50px);
} }

View File

@ -1,243 +1,243 @@
<template> <template>
<div :class="['message-input', !isPC && 'message-input-h5']"> <div :class="['message-input', !isPC && 'message-input-h5']">
<div class="audio-main-content-line"> <div class="audio-main-content-line">
<MessageInputAudio <MessageInputAudio
v-if="(isWeChat || isApp) && isRenderVoice" v-if="(isWeChat || isApp) && isRenderVoice"
:class="{ :class="{
'message-input-wx-audio-open': displayType === 'audio', 'message-input-wx-audio-open': displayType === 'audio',
}" }"
:isEnableAudio="displayType === 'audio'" :isEnableAudio="displayType === 'audio'"
@changeDisplayType="changeDisplayType" @changeDisplayType="changeDisplayType"
/> />
<MessageInputEditor <MessageInputEditor
v-show="displayType === 'editor'" v-show="displayType === 'editor'"
ref="editor" ref="editor"
class="message-input-editor" class="message-input-editor"
:placeholder="props.placeholder" :placeholder="props.placeholder"
:isMuted="props.isMuted" :isMuted="props.isMuted"
:muteText="props.muteText" :muteText="props.muteText"
:enableInput="props.enableInput" :enableInput="props.enableInput"
:enableAt="props.enableAt" :enableAt="props.enableAt"
:enableTyping="props.enableTyping" :enableTyping="props.enableTyping"
:isGroup="isGroup" :isGroup="isGroup"
@onTyping="onTyping" @onTyping="onTyping"
@onAt="onAt" @onAt="onAt"
@onFocus="onFocus" @onFocus="onFocus"
/> />
<MessageInputAt <MessageInputAt
v-if="props.enableAt" v-if="props.enableAt"
ref="messageInputAtRef" ref="messageInputAtRef"
@insertAt="insertAt" @insertAt="insertAt"
@onAtListOpen="onAtListOpen" @onAtListOpen="onAtListOpen"
/> />
<Icon <Icon
v-if="isRenderEmojiPicker" v-if="isRenderEmojiPicker"
class="icon icon-face" class="icon icon-face"
:file="faceIcon" :file="faceIcon"
:size="'23px'" :size="'23px'"
:hotAreaSize="'3px'" :hotAreaSize="'3px'"
@onClick="changeToolbarDisplayType('emojiPicker')" @onClick="changeToolbarDisplayType('emojiPicker')"
/> />
<Icon <Icon
v-if="isRenderMore" v-if="isRenderMore"
class="icon icon-more" class="icon icon-more"
:file="moreIcon" :file="moreIcon"
:size="'23px'" :size="'23px'"
:hotAreaSize="'3px'" :hotAreaSize="'3px'"
@onClick="changeToolbarDisplayType('tools')" @onClick="changeToolbarDisplayType('tools')"
/> />
</div> </div>
<div> <div>
<MessageQuote <MessageQuote
:style="{minWidth: 0}" :style="{minWidth: 0}"
:displayType="displayType" :displayType="displayType"
/> />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import TUIChatEngine, { import TUIChatEngine, {
TUIStore, TUIStore,
StoreName, StoreName,
IMessageModel, IMessageModel,
IConversationModel, IConversationModel,
} from '@tencentcloud/chat-uikit-engine'; } from '@tencentcloud/chat-uikit-engine';
import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue'; import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue';
import MessageInputEditor from './message-input-editor.vue'; import MessageInputEditor from './message-input-editor.vue';
import MessageInputAt from './message-input-at/index.vue'; import MessageInputAt from './message-input-at/index.vue';
import MessageInputAudio from './message-input-audio.vue'; import MessageInputAudio from './message-input-audio.vue';
import MessageQuote from './message-input-quote/index.vue'; import MessageQuote from './message-input-quote/index.vue';
import Icon from '../../common/Icon.vue'; import Icon from '../../common/Icon.vue';
import faceIcon from '../../../assets/icon/face-uni.png'; import faceIcon from '../../../assets/icon/face-uni.png';
import moreIcon from '../../../assets/icon/more-uni.png'; import moreIcon from '../../../assets/icon/more-uni.png';
import { isPC, isH5, isWeChat, isApp } from '../../../utils/env'; import { isPC, isH5, isWeChat, isApp } from '../../../utils/env';
import { sendTyping } from '../utils/sendMessage'; import { sendTyping } from '../utils/sendMessage';
import { ToolbarDisplayType, InputDisplayType } from '../../../interface'; import { ToolbarDisplayType, InputDisplayType } from '../../../interface';
import TUIChatConfig from '../config'; import TUIChatConfig from '../config';
interface IProps { interface IProps {
placeholder: string; placeholder: string;
isMuted?: boolean; isMuted?: boolean;
muteText?: string; muteText?: string;
enableInput?: boolean; enableInput?: boolean;
enableAt?: boolean; enableAt?: boolean;
enableTyping?: boolean; enableTyping?: boolean;
replyOrReference?: Record<string, any>; replyOrReference?: Record<string, any>;
inputToolbarDisplayType: ToolbarDisplayType; inputToolbarDisplayType: ToolbarDisplayType;
} }
interface IEmits { interface IEmits {
(e: 'changeToolbarDisplayType', displayType: ToolbarDisplayType): void; (e: 'changeToolbarDisplayType', displayType: ToolbarDisplayType): void;
} }
const emits = defineEmits<IEmits>(); const emits = defineEmits<IEmits>();
const props = withDefaults(defineProps<IProps>(), { const props = withDefaults(defineProps<IProps>(), {
placeholder: 'this is placeholder', placeholder: 'this is placeholder',
replyOrReference: () => ({}), replyOrReference: () => ({}),
isMuted: true, isMuted: true,
muteText: '', muteText: '',
enableInput: true, enableInput: true,
enableAt: true, enableAt: true,
enableTyping: true, enableTyping: true,
inputToolbarDisplayType: 'none', inputToolbarDisplayType: 'none',
}); });
const editor = ref(); const editor = ref();
const messageInputAtRef = ref(); const messageInputAtRef = ref();
const currentConversation = ref<IConversationModel>(); const currentConversation = ref<IConversationModel>();
const isGroup = ref<boolean>(false); const isGroup = ref<boolean>(false);
const displayType = ref<InputDisplayType>('editor'); const displayType = ref<InputDisplayType>('editor');
const featureConfig = TUIChatConfig.getFeatureConfig(); const featureConfig = TUIChatConfig.getFeatureConfig();
const isRenderVoice = ref<boolean>(featureConfig.InputVoice); const isRenderVoice = ref<boolean>(featureConfig.InputVoice);
const isRenderEmojiPicker = ref<boolean>(featureConfig.InputEmoji || featureConfig.InputStickers); const isRenderEmojiPicker = ref<boolean>(featureConfig.InputEmoji || featureConfig.InputStickers);
const isRenderMore = ref<boolean>(featureConfig.InputImage || featureConfig.InputVideo || featureConfig.InputEvaluation || featureConfig.InputQuickReplies); const isRenderMore = ref<boolean>(featureConfig.InputImage || featureConfig.InputVideo || featureConfig.InputEvaluation || featureConfig.InputQuickReplies);
onMounted(() => { onMounted(() => {
TUIStore.watch(StoreName.CONV, { TUIStore.watch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdated, currentConversation: onCurrentConversationUpdated,
}); });
TUIStore.watch(StoreName.CHAT, { TUIStore.watch(StoreName.CHAT, {
quoteMessage: onQuoteMessageUpdated, quoteMessage: onQuoteMessageUpdated,
}); });
}); });
onUnmounted(() => { onUnmounted(() => {
TUIStore.unwatch(StoreName.CONV, { TUIStore.unwatch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdated, currentConversation: onCurrentConversationUpdated,
}); });
TUIStore.unwatch(StoreName.CHAT, { TUIStore.unwatch(StoreName.CHAT, {
quoteMessage: onQuoteMessageUpdated, quoteMessage: onQuoteMessageUpdated,
}); });
}); });
watch(() => props.inputToolbarDisplayType, (newVal: ToolbarDisplayType) => { watch(() => props.inputToolbarDisplayType, (newVal: ToolbarDisplayType) => {
if (newVal !== 'none') { if (newVal !== 'none') {
changeDisplayType('editor'); changeDisplayType('editor');
} }
}); });
function changeDisplayType(display: InputDisplayType) { function changeDisplayType(display: InputDisplayType) {
displayType.value = display; displayType.value = display;
if (display === 'audio') { if (display === 'audio') {
emits('changeToolbarDisplayType', 'none'); emits('changeToolbarDisplayType', 'none');
} }
} }
function changeToolbarDisplayType(displayType: ToolbarDisplayType) { function changeToolbarDisplayType(displayType: ToolbarDisplayType) {
emits('changeToolbarDisplayType', displayType); emits('changeToolbarDisplayType', displayType);
} }
const onTyping = (inputContentEmpty: boolean, inputBlur: boolean) => { const onTyping = (inputContentEmpty: boolean, inputBlur: boolean) => {
sendTyping(inputContentEmpty, inputBlur); sendTyping(inputContentEmpty, inputBlur);
}; };
const onAt = (show: boolean) => { const onAt = (show: boolean) => {
messageInputAtRef?.value?.toggleAtList(show); messageInputAtRef?.value?.toggleAtList(show);
}; };
const onFocus = () => { const onFocus = () => {
// if (isH5) { // if (isH5) {
emits('changeToolbarDisplayType', 'none'); emits('changeToolbarDisplayType', 'none');
// } // }
// //
// emits('changeToolbarDisplayType', 'none'); // emits('changeToolbarDisplayType', 'none');
}; };
const insertEmoji = (emoji: any) => { const insertEmoji = (emoji: any) => {
editor?.value?.addEmoji && editor?.value?.addEmoji(emoji); editor?.value?.addEmoji && editor?.value?.addEmoji(emoji);
}; };
const insertAt = (atInfo: any) => { const insertAt = (atInfo: any) => {
editor?.value?.insertAt && editor?.value?.insertAt(atInfo); editor?.value?.insertAt && editor?.value?.insertAt(atInfo);
}; };
const onAtListOpen = () => { const onAtListOpen = () => {
editor?.value?.blur && editor?.value?.blur(); editor?.value?.blur && editor?.value?.blur();
}; };
const reEdit = (content: any) => { const reEdit = (content: any) => {
editor?.value?.resetEditor(); editor?.value?.resetEditor();
editor?.value?.setEditorContent(content); editor?.value?.setEditorContent(content);
}; };
function onCurrentConversationUpdated(conversation: IConversationModel) { function onCurrentConversationUpdated(conversation: IConversationModel) {
currentConversation.value = conversation; currentConversation.value = conversation;
isGroup.value = currentConversation.value?.type === TUIChatEngine.TYPES.CONV_GROUP; isGroup.value = currentConversation.value?.type === TUIChatEngine.TYPES.CONV_GROUP;
} }
function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) { function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) {
// switch text input mode when there is a quote message // switch text input mode when there is a quote message
if (options?.message && options?.type === 'quote') { if (options?.message && options?.type === 'quote') {
changeDisplayType('editor'); changeDisplayType('editor');
} }
} }
defineExpose({ defineExpose({
insertEmoji, insertEmoji,
reEdit, reEdit,
}); });
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "../../../assets/styles/common"; @import "../../../assets/styles/common";
:not(not) { :not(not) {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
min-width: 0; min-width: 0;
box-sizing: border-box; box-sizing: border-box;
} }
.message-input { .message-input {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border: none; border: none;
overflow: hidden; overflow: hidden;
background: #ebf0f6; background: #ebf0f6;
&-h5 { &-h5 {
padding: 10px 10px 15px; padding: 10px 10px 15px;
} }
&-editor { &-editor {
flex: 1; flex: 1;
display: flex; display: flex;
} }
.icon { .icon {
margin-left: 3px; margin-left: 3px;
} }
&-wx-audio-open { &-wx-audio-open {
flex: 1; flex: 1;
} }
} }
.audio-main-content-line { .audio-main-content-line {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
} }
</style> </style>

View File

@ -1,285 +1,285 @@
<template> <template>
<div <div
:class="{ :class="{
'message-input-container': true, 'message-input-container': true,
'message-input-container-h5': !isPC, 'message-input-container-h5': !isPC,
}" }"
> >
<div <div
v-if="props.isMuted" v-if="props.isMuted"
class="message-input-mute" class="message-input-mute"
> >
{{ props.muteText }} {{ props.muteText }}
</div> </div>
<input <input
id="editor" id="editor"
ref="inputRef" ref="inputRef"
v-model="inputText" v-model="inputText"
:adjust-position="true" :adjust-position="true"
cursor-spacing="20" cursor-spacing="20"
confirm-type="send" confirm-type="send"
:confirm-hold="true" :confirm-hold="true"
maxlength="140" maxlength="140"
type="text" type="text"
placeholder-class="input-placeholder" placeholder-class="input-placeholder"
class="message-input-area" class="message-input-area"
:placeholder="props.placeholder" :placeholder="props.placeholder"
auto-blur auto-blur
@confirm="handleSendMessage" @confirm="handleSendMessage"
@input="onInput" @input="onInput"
@blur="onBlur" @blur="onBlur"
@focus="onFocus" @focus="onFocus"
> >
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue'; import { ref, watch, onMounted, onUnmounted } from '../../../adapter-vue';
import { TUIStore, StoreName, IConversationModel, IMessageModel } from '@tencentcloud/chat-uikit-engine'; import { TUIStore, StoreName, IConversationModel, IMessageModel } from '@tencentcloud/chat-uikit-engine';
import { TUIGlobal } from '@tencentcloud/universal-api'; import { TUIGlobal } from '@tencentcloud/universal-api';
import DraftManager from '../utils/conversationDraft'; import DraftManager from '../utils/conversationDraft';
import { transformTextWithEmojiNamesToKeys } from '../emoji-config'; import { transformTextWithEmojiNamesToKeys } from '../emoji-config';
import { isPC } from '../../../utils/env'; import { isPC } from '../../../utils/env';
import { sendMessages } from '../utils/sendMessage'; import { sendMessages } from '../utils/sendMessage';
import { ISendMessagePayload } from '../../../interface'; import { ISendMessagePayload } from '../../../interface';
const props = defineProps({ const props = defineProps({
placeholder: { placeholder: {
type: String, type: String,
default: 'this is placeholder', default: 'this is placeholder',
}, },
replayOrReferenceMessage: { replayOrReferenceMessage: {
type: Object, type: Object,
default: () => ({}), default: () => ({}),
required: false, required: false,
}, },
isMuted: { isMuted: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
muteText: { muteText: {
type: String, type: String,
default: '', default: '',
}, },
enableInput: { enableInput: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
enableAt: { enableAt: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
enableTyping: { enableTyping: {
type: Boolean, type: Boolean,
default: true, default: true,
}, },
isGroup: { isGroup: {
type: Boolean, type: Boolean,
default: false, default: false,
}, },
}); });
const emits = defineEmits(['onTyping', 'onFocus', 'onAt']); const emits = defineEmits(['onTyping', 'onFocus', 'onAt']);
const inputText = ref(''); const inputText = ref('');
const inputRef = ref(); const inputRef = ref();
const inputBlur = ref(true); const inputBlur = ref(true);
const inputContentEmpty = ref(true); const inputContentEmpty = ref(true);
const allInsertedAtInfo = new Map(); const allInsertedAtInfo = new Map();
const currentConversation = ref<IConversationModel>(); const currentConversation = ref<IConversationModel>();
const currentConversationID = ref<string>(''); const currentConversationID = ref<string>('');
const currentQuoteMessage = ref<{ message: IMessageModel; type: string }>(); const currentQuoteMessage = ref<{ message: IMessageModel; type: string }>();
onMounted(() => { onMounted(() => {
TUIStore.watch(StoreName.CONV, { TUIStore.watch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdated, currentConversation: onCurrentConversationUpdated,
}); });
TUIStore.watch(StoreName.CHAT, { TUIStore.watch(StoreName.CHAT, {
quoteMessage: onQuoteMessageUpdated, quoteMessage: onQuoteMessageUpdated,
}); });
uni.$on('insert-emoji', (data) => { uni.$on('insert-emoji', (data) => {
inputText.value += data?.emoji?.name; inputText.value += data?.emoji?.name;
}); });
uni.$on('send-message-in-emoji-picker', () => { uni.$on('send-message-in-emoji-picker', () => {
handleSendMessage(); handleSendMessage();
}); });
}); });
onUnmounted(() => { onUnmounted(() => {
if (currentConversationID.value) { if (currentConversationID.value) {
DraftManager.setStore(currentConversationID.value, inputText.value, inputText.value, currentQuoteMessage.value); DraftManager.setStore(currentConversationID.value, inputText.value, inputText.value, currentQuoteMessage.value);
} }
uni.$off('insertEmoji'); uni.$off('insertEmoji');
uni.$off('send-message-in-emoji-picker'); uni.$off('send-message-in-emoji-picker');
TUIStore.unwatch(StoreName.CONV, { TUIStore.unwatch(StoreName.CONV, {
currentConversation: onCurrentConversationUpdated, currentConversation: onCurrentConversationUpdated,
}); });
TUIStore.unwatch(StoreName.CHAT, { TUIStore.unwatch(StoreName.CHAT, {
quoteMessage: onQuoteMessageUpdated, quoteMessage: onQuoteMessageUpdated,
}); });
reset(); reset();
}); });
const handleSendMessage = () => { const handleSendMessage = () => {
const messageList = getEditorContent(); const messageList = getEditorContent();
resetEditor(); resetEditor();
sendMessages(messageList as any, currentConversation.value!); sendMessages(messageList as any, currentConversation.value!);
}; };
const insertAt = (atInfo: any) => { const insertAt = (atInfo: any) => {
if (!allInsertedAtInfo?.has(atInfo?.id)) { if (!allInsertedAtInfo?.has(atInfo?.id)) {
allInsertedAtInfo?.set(atInfo?.id, atInfo?.label); allInsertedAtInfo?.set(atInfo?.id, atInfo?.label);
} }
inputText.value += atInfo?.label; inputText.value += atInfo?.label;
}; };
const getEditorContent = () => { const getEditorContent = () => {
let text = inputText.value; let text = inputText.value;
text = transformTextWithEmojiNamesToKeys(text); text = transformTextWithEmojiNamesToKeys(text);
const atUserList: string[] = []; const atUserList: string[] = [];
allInsertedAtInfo?.forEach((value: string, key: string) => { allInsertedAtInfo?.forEach((value: string, key: string) => {
if (text?.includes('@' + value)) { if (text?.includes('@' + value)) {
atUserList.push(key); atUserList.push(key);
} }
}); });
const payload: ISendMessagePayload = { const payload: ISendMessagePayload = {
text, text,
}; };
if (atUserList?.length) { if (atUserList?.length) {
payload.atUserList = atUserList; payload.atUserList = atUserList;
} }
return [ return [
{ {
type: 'text', type: 'text',
payload, payload,
}, },
]; ];
}; };
const resetEditor = () => { const resetEditor = () => {
inputText.value = ''; inputText.value = '';
inputContentEmpty.value = true; inputContentEmpty.value = true;
allInsertedAtInfo?.clear(); allInsertedAtInfo?.clear();
}; };
const setEditorContent = (content: any) => { const setEditorContent = (content: any) => {
inputText.value = content; inputText.value = content;
}; };
const onBlur = () => { const onBlur = () => {
inputBlur.value = true; inputBlur.value = true;
}; };
const onFocus = (e: any) => { const onFocus = (e: any) => {
inputBlur.value = false; inputBlur.value = false;
emits('onFocus', e?.detail?.height); emits('onFocus', e?.detail?.height);
}; };
const isEditorContentEmpty = () => { const isEditorContentEmpty = () => {
inputContentEmpty.value = inputText?.value?.length ? false : true; inputContentEmpty.value = inputText?.value?.length ? false : true;
}; };
const onInput = (e: any) => { const onInput = (e: any) => {
// uni-app recognizes mention messages // uni-app recognizes mention messages
const text = e?.detail?.value; const text = e?.detail?.value;
isEditorContentEmpty(); isEditorContentEmpty();
if (props.isGroup && (text.endsWith('@') || text.endsWith('@\n'))) { if (props.isGroup && (text.endsWith('@') || text.endsWith('@\n'))) {
// TUIGlobal?.hideKeyboard(); // TUIGlobal?.hideKeyboard();
emits('onAt', true); emits('onAt', true);
} }
}; };
watch( watch(
() => [inputContentEmpty.value, inputBlur.value], () => [inputContentEmpty.value, inputBlur.value],
(newVal: any, oldVal: any) => { (newVal: any, oldVal: any) => {
if (newVal !== oldVal) { if (newVal !== oldVal) {
emits('onTyping', inputContentEmpty.value, inputBlur.value); emits('onTyping', inputContentEmpty.value, inputBlur.value);
} }
}, },
{ {
immediate: true, immediate: true,
deep: true, deep: true,
}, },
); );
function onCurrentConversationUpdated(conversation: IConversationModel) { function onCurrentConversationUpdated(conversation: IConversationModel) {
const prevConversationID = currentConversationID.value; const prevConversationID = currentConversationID.value;
currentConversation.value = conversation; currentConversation.value = conversation;
currentConversationID.value = conversation?.conversationID; currentConversationID.value = conversation?.conversationID;
if (prevConversationID !== currentConversationID.value) { if (prevConversationID !== currentConversationID.value) {
if (prevConversationID) { if (prevConversationID) {
DraftManager.setStore( DraftManager.setStore(
prevConversationID, prevConversationID,
inputText.value, inputText.value,
inputText.value, inputText.value,
currentQuoteMessage.value, currentQuoteMessage.value,
); );
} }
resetEditor(); resetEditor();
if (currentConversationID.value) { if (currentConversationID.value) {
DraftManager.getStore(currentConversationID.value, setEditorContent); DraftManager.getStore(currentConversationID.value, setEditorContent);
} }
} }
} }
function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) { function onQuoteMessageUpdated(options?: { message: IMessageModel; type: string }) {
currentQuoteMessage.value = options; currentQuoteMessage.value = options;
} }
function reset() { function reset() {
inputBlur.value = true; inputBlur.value = true;
currentConversation.value = null; currentConversation.value = null;
currentConversationID.value = ''; currentConversationID.value = '';
currentQuoteMessage.value = null; currentQuoteMessage.value = null;
resetEditor(); resetEditor();
} }
defineExpose({ defineExpose({
insertAt, insertAt,
resetEditor, resetEditor,
setEditorContent, setEditorContent,
getEditorContent, getEditorContent,
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../../../assets/styles/common"; @import "../../../assets/styles/common";
.message-input-container { .message-input-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
flex: 1; flex: 1;
padding: 3px 10px 10px; padding: 3px 10px 10px;
overflow: hidden; overflow: hidden;
&-h5 { &-h5 {
flex: 1; flex: 1;
height: auto; height: auto;
background: #fff; background: #fff;
border-radius: 10px; border-radius: 10px;
padding: 7px 0 7px 10px; padding: 7px 0 7px 10px;
font-size: 16px !important; font-size: 16px !important;
max-height: 86px; max-height: 86px;
} }
.message-input-mute { .message-input-mute {
flex: 1; flex: 1;
display: flex; display: flex;
color: #999; color: #999;
font-size: 14px; font-size: 14px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.message-input-area { .message-input-area {
flex: 1; flex: 1;
overflow-y: scroll; overflow-y: scroll;
min-height: 25px; min-height: 25px;
} }
} }
</style> </style>

View File

@ -1,430 +1,430 @@
<template> <template>
<div <div
:style="{height: '100%'}" :style="{height: '100%'}"
v-if="typeof contactInfoData === 'object' && Object.keys(contactInfoData).length" v-if="typeof contactInfoData === 'object' && Object.keys(contactInfoData).length"
:class="['tui-contact-info', !isPC && 'tui-contact-info-h5']" :class="['tui-contact-info', !isPC && 'tui-contact-info-h5']"
> >
<div <div
v-if="!isPC" v-if="!isPC"
:class="[ :class="[
'tui-contact-info-header', 'tui-contact-info-header',
!isPC && 'tui-contact-info-h5-header', !isPC && 'tui-contact-info-h5-header',
]" ]"
> >
<div <div
:class="[ :class="[
'tui-contact-info-header-icon', 'tui-contact-info-header-icon',
!isPC && 'tui-contact-info-h5-header-icon', !isPC && 'tui-contact-info-h5-header-icon',
]" ]"
@click="resetContactSearchingUIData" @click="resetContactSearchingUIData"
> >
<Icon :file="backSVG" /> <Icon :file="backSVG" />
</div> </div>
<div <div
:class="[ :class="[
'tui-contact-info-header-title', 'tui-contact-info-header-title',
!isPC && 'tui-contact-info-h5-header-title', !isPC && 'tui-contact-info-h5-header-title',
]" ]"
> >
{{ TUITranslateService.t("TUIContact.添加好友/群聊") }} {{ TUITranslateService.t("TUIContact.添加好友/群聊") }}
</div> </div>
</div> </div>
<div :class="['tui-contact-info-basic', !isPC && 'tui-contact-info-h5-basic']"> <div :class="['tui-contact-info-basic', !isPC && 'tui-contact-info-h5-basic']">
<div <div
:class="[ :class="[
'tui-contact-info-basic-text', 'tui-contact-info-basic-text',
!isPC && 'tui-contact-info-h5-basic-text', !isPC && 'tui-contact-info-h5-basic-text',
]" ]"
> >
<div <div
:class="[ :class="[
'tui-contact-info-basic-text-name', 'tui-contact-info-basic-text-name',
!isPC && 'tui-contact-info-h5-basic-text-name', !isPC && 'tui-contact-info-h5-basic-text-name',
]" ]"
> >
{{ generateContactInfoName(contactInfoData) }} {{ generateContactInfoName(contactInfoData) }}
</div> </div>
<div <div
v-for="item in contactInfoBasicList" v-for="item in contactInfoBasicList"
:key="item.label" :key="item.label"
:class="[ :class="[
'tui-contact-info-basic-text-other', 'tui-contact-info-basic-text-other',
!isPC && 'tui-contact-info-h5-basic-text-other', !isPC && 'tui-contact-info-h5-basic-text-other',
]" ]"
> >
{{ {{
`${TUITranslateService.t(`TUIContact.${item.label}`)}: `${TUITranslateService.t(`TUIContact.${item.label}`)}:
${item.data}` ${item.data}`
}} }}
</div> </div>
</div> </div>
<img <img
:class="[ :class="[
'tui-contact-info-basic-avatar', 'tui-contact-info-basic-avatar',
!isPC && 'tui-contact-info-h5-basic-avatar', !isPC && 'tui-contact-info-h5-basic-avatar',
]" ]"
:src="generateAvatar(contactInfoData)" :src="generateAvatar(contactInfoData)"
> >
</div> </div>
<div <div
v-if="contactInfoMoreList[0]" v-if="contactInfoMoreList[0]"
:class="['tui-contact-info-more', !isPC && 'tui-contact-info-h5-more']" :class="['tui-contact-info-more', !isPC && 'tui-contact-info-h5-more']"
> >
<div <div
v-for="item in contactInfoMoreList" v-for="item in contactInfoMoreList"
:key="item.key" :key="item.key"
:class="[ :class="[
'tui-contact-info-more-item', 'tui-contact-info-more-item',
!isPC && 'tui-contact-info-h5-more-item', !isPC && 'tui-contact-info-h5-more-item',
item.labelPosition === CONTACT_INFO_LABEL_POSITION.TOP item.labelPosition === CONTACT_INFO_LABEL_POSITION.TOP
? 'tui-contact-info-more-item-top' ? 'tui-contact-info-more-item-top'
: 'tui-contact-info-more-item-left', : 'tui-contact-info-more-item-left',
]" ]"
> >
<div <div
:class="[ :class="[
'tui-contact-info-more-item-label', 'tui-contact-info-more-item-label',
!isPC && 'tui-contact-info-h5-more-item-label', !isPC && 'tui-contact-info-h5-more-item-label',
]" ]"
> >
{{ `${TUITranslateService.t(`TUIContact.${item.label}`)}` }} {{ `${TUITranslateService.t(`TUIContact.${item.label}`)}` }}
</div> </div>
<div <div
:class="[ :class="[
'tui-contact-info-more-item-content', 'tui-contact-info-more-item-content',
!isPC && 'tui-contact-info-h5-more-item-content', !isPC && 'tui-contact-info-h5-more-item-content',
]" ]"
> >
<div <div
v-if="!item.editing" v-if="!item.editing"
:class="[ :class="[
'tui-contact-info-more-item-content-text', 'tui-contact-info-more-item-content-text',
!isPC && 'tui-contact-info-h5-more-item-content-text', !isPC && 'tui-contact-info-h5-more-item-content-text',
]" ]"
> >
<div <div
:class="[ :class="[
'tui-contact-info-more-item-content-text-data', 'tui-contact-info-more-item-content-text-data',
!isPC && 'tui-contact-info-h5-more-item-content-text-data', !isPC && 'tui-contact-info-h5-more-item-content-text-data',
]" ]"
> >
{{ item.data }} {{ item.data }}
</div> </div>
<div <div
v-if="item.editable" v-if="item.editable"
:class="[ :class="[
'tui-contact-info-more-item-content-text-icon', 'tui-contact-info-more-item-content-text-icon',
!isPC && 'tui-contact-info-h5-more-item-content-text-icon', !isPC && 'tui-contact-info-h5-more-item-content-text-icon',
]" ]"
@click="setEditing(item)" @click="setEditing(item)"
> >
<Icon <Icon
:file="editSVG" :file="editSVG"
width="14px" width="14px"
height="14px" height="14px"
/> />
</div> </div>
</div> </div>
<input <input
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.INPUT" v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.INPUT"
v-model="item.data" v-model="item.data"
:class="[ :class="[
'tui-contact-info-more-item-content-input', 'tui-contact-info-more-item-content-input',
!isPC && 'tui-contact-info-h5-more-item-content-input', !isPC && 'tui-contact-info-h5-more-item-content-input',
]" ]"
type="text" type="text"
@confirm="onContactInfoEmitSubmit(item)" @confirm="onContactInfoEmitSubmit(item)"
@keyup.enter="onContactInfoEmitSubmit(item)" @keyup.enter="onContactInfoEmitSubmit(item)"
> >
<textarea <textarea
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.TEXTAREA" v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.TEXTAREA"
v-model="item.data" v-model="item.data"
:class="[ :class="[
'tui-contact-info-more-item-content-textarea', 'tui-contact-info-more-item-content-textarea',
!isPC && 'tui-contact-info-h5-more-item-content-textarea', !isPC && 'tui-contact-info-h5-more-item-content-textarea',
]" ]"
confirm-type="done" confirm-type="done"
/> />
<div <div
v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.SWITCH" v-else-if="item.editType === CONTACT_INFO_MORE_EDIT_TYPE.SWITCH"
@click="onContactInfoEmitSubmit(item)" @click="onContactInfoEmitSubmit(item)"
> >
<SwitchBar :value="item.data" /> <SwitchBar :value="item.data" />
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div <div
:class="[ :class="[
'tui-contact-info-button', 'tui-contact-info-button',
!isPC && 'tui-contact-info-h5-button', !isPC && 'tui-contact-info-h5-button',
]" ]"
> >
<button <button
v-for="item in contactInfoButtonList" v-for="item in contactInfoButtonList"
:key="item.key" :key="item.key"
:class="[ :class="[
'tui-contact-info-button-item', 'tui-contact-info-button-item',
!isPC && 'tui-contact-info-h5-button-item', !isPC && 'tui-contact-info-h5-button-item',
item.type === CONTACT_INFO_BUTTON_TYPE.CANCEL item.type === CONTACT_INFO_BUTTON_TYPE.CANCEL
? `tui-contact-info-button-item-cancel` ? `tui-contact-info-button-item-cancel`
: `tui-contact-info-button-item-submit`, : `tui-contact-info-button-item-submit`,
]" ]"
@click="onContactInfoButtonClicked(item)" @click="onContactInfoButtonClicked(item)"
> >
{{ TUITranslateService.t(`TUIContact.${item.label}`) }} {{ TUITranslateService.t(`TUIContact.${item.label}`) }}
</button> </button>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import TUIChatEngine, { import TUIChatEngine, {
TUIStore, TUIStore,
StoreName, StoreName,
TUITranslateService, TUITranslateService,
IGroupModel, IGroupModel,
Friend, Friend,
FriendApplication, FriendApplication,
} from '@tencentcloud/chat-uikit-engine'; } from '@tencentcloud/chat-uikit-engine';
import { TUIGlobal } from '@tencentcloud/universal-api'; import { TUIGlobal } from '@tencentcloud/universal-api';
import { ref, computed, onMounted, onUnmounted } from '../../../adapter-vue'; import { ref, computed, onMounted, onUnmounted } from '../../../adapter-vue';
import { isPC } from '../../../utils/env'; import { isPC } from '../../../utils/env';
import { import {
generateAvatar, generateAvatar,
generateContactInfoName, generateContactInfoName,
generateContactInfoBasic, generateContactInfoBasic,
isFriend, isFriend,
isApplicationType, isApplicationType,
} from '../utils/index'; } from '../utils/index';
import { import {
contactMoreInfoConfig, contactMoreInfoConfig,
contactButtonConfig, contactButtonConfig,
} from './contact-info-config'; } from './contact-info-config';
import Icon from '../../common/Icon.vue'; import Icon from '../../common/Icon.vue';
import editSVG from '../../../assets/icon/edit.svg'; import editSVG from '../../../assets/icon/edit.svg';
import backSVG from '../../../assets/icon/back.svg'; import backSVG from '../../../assets/icon/back.svg';
import SwitchBar from '../../common/SwitchBar/index.vue'; import SwitchBar from '../../common/SwitchBar/index.vue';
import { import {
IBlackListUserItem, IBlackListUserItem,
IContactInfoMoreItem, IContactInfoMoreItem,
IContactInfoButton, IContactInfoButton,
} from '../../../interface'; } from '../../../interface';
import { import {
CONTACT_INFO_LABEL_POSITION, CONTACT_INFO_LABEL_POSITION,
CONTACT_INFO_MORE_EDIT_TYPE, CONTACT_INFO_MORE_EDIT_TYPE,
CONTACT_INFO_BUTTON_TYPE, CONTACT_INFO_BUTTON_TYPE,
} from '../../../constant'; } from '../../../constant';
import { deepCopy } from '../../TUIChat/utils/utils'; import { deepCopy } from '../../TUIChat/utils/utils';
type IContactInfoType = IGroupModel | Friend | FriendApplication | IBlackListUserItem; type IContactInfoType = IGroupModel | Friend | FriendApplication | IBlackListUserItem;
const emits = defineEmits(['switchConversation']); const emits = defineEmits(['switchConversation']);
const contactInfoData = ref<IContactInfoType>({} as IContactInfoType); const contactInfoData = ref<IContactInfoType>({} as IContactInfoType);
const contactInfoBasicList = ref<Array<{ label: string; data: string }>>([]); const contactInfoBasicList = ref<Array<{ label: string; data: string }>>([]);
const contactInfoMoreList = ref<IContactInfoMoreItem[]>([]); const contactInfoMoreList = ref<IContactInfoMoreItem[]>([]);
const contactInfoButtonList = ref<IContactInfoButton[]>([]); const contactInfoButtonList = ref<IContactInfoButton[]>([]);
const setEditing = (item: any) => { const setEditing = (item: any) => {
item.editing = true; item.editing = true;
}; };
const isGroup = computed((): boolean => const isGroup = computed((): boolean =>
(contactInfoData.value as IGroupModel)?.groupID ? true : false, (contactInfoData.value as IGroupModel)?.groupID ? true : false,
); );
const isApplication = computed((): boolean => { const isApplication = computed((): boolean => {
return isApplicationType(contactInfoData?.value); return isApplicationType(contactInfoData?.value);
}); });
// is both friend, if is group type always false // is both friend, if is group type always false
const isBothFriend = ref<boolean>(false); const isBothFriend = ref<boolean>(false);
// is group member, including ordinary member, admin, group owner // is group member, including ordinary member, admin, group owner
const isGroupMember = computed((): boolean => { const isGroupMember = computed((): boolean => {
return (contactInfoData.value as IGroupModel)?.selfInfo?.userID ? true : false; return (contactInfoData.value as IGroupModel)?.selfInfo?.userID ? true : false;
}); });
// is in black list, if is group type always false // is in black list, if is group type always false
const isInBlackList = computed((): boolean => { const isInBlackList = computed((): boolean => {
return ( return (
!isGroup.value !isGroup.value
&& blackList.value?.findIndex( && blackList.value?.findIndex(
(item: IBlackListUserItem) => (item: IBlackListUserItem) =>
item?.userID === (contactInfoData.value as IBlackListUserItem)?.userID, item?.userID === (contactInfoData.value as IBlackListUserItem)?.userID,
) >= 0 ) >= 0
); );
}); });
const blackList = ref<IBlackListUserItem[]>([]); const blackList = ref<IBlackListUserItem[]>([]);
onMounted(() => { onMounted(() => {
TUIStore.watch(StoreName.CUSTOM, { TUIStore.watch(StoreName.CUSTOM, {
currentContactInfo: onCurrentContactInfoUpdated, currentContactInfo: onCurrentContactInfoUpdated,
}); });
TUIStore.watch(StoreName.USER, { TUIStore.watch(StoreName.USER, {
userBlacklist: onUserBlacklistUpdated, userBlacklist: onUserBlacklistUpdated,
}); });
}); });
onUnmounted(() => { onUnmounted(() => {
TUIStore.unwatch(StoreName.CUSTOM, { TUIStore.unwatch(StoreName.CUSTOM, {
currentContactInfo: onCurrentContactInfoUpdated, currentContactInfo: onCurrentContactInfoUpdated,
}); });
TUIStore.unwatch(StoreName.USER, { TUIStore.unwatch(StoreName.USER, {
userBlacklist: onUserBlacklistUpdated, userBlacklist: onUserBlacklistUpdated,
}); });
}); });
const resetContactInfoUIData = () => { const resetContactInfoUIData = () => {
contactInfoData.value = {} as IContactInfoType; contactInfoData.value = {} as IContactInfoType;
contactInfoBasicList.value = []; contactInfoBasicList.value = [];
contactInfoMoreList.value = []; contactInfoMoreList.value = [];
contactInfoButtonList.value = []; contactInfoButtonList.value = [];
}; };
const resetContactSearchingUIData = () => { const resetContactSearchingUIData = () => {
TUIStore.update(StoreName.CUSTOM, 'currentContactInfo', {}); TUIStore.update(StoreName.CUSTOM, 'currentContactInfo', {});
TUIStore.update(StoreName.CUSTOM, 'currentContactSearchingStatus', false); TUIStore.update(StoreName.CUSTOM, 'currentContactSearchingStatus', false);
TUIGlobal?.closeSearching && TUIGlobal?.closeSearching(); TUIGlobal?.closeSearching && TUIGlobal?.closeSearching();
}; };
const onContactInfoEmitSubmit = (item: any) => { const onContactInfoEmitSubmit = (item: any) => {
item.editSubmitHandler item.editSubmitHandler
&& item.editSubmitHandler({ && item.editSubmitHandler({
item, item,
contactInfoData: contactInfoData.value, contactInfoData: contactInfoData.value,
isBothFriend: isBothFriend.value, isBothFriend: isBothFriend.value,
isInBlackList: isInBlackList.value, isInBlackList: isInBlackList.value,
}); });
}; };
const onContactInfoButtonClicked = (item: any) => { const onContactInfoButtonClicked = (item: any) => {
item.onClick item.onClick
&& item.onClick({ && item.onClick({
contactInfoData: contactInfoData.value, contactInfoData: contactInfoData.value,
contactInfoMoreList: contactInfoMoreList.value, contactInfoMoreList: contactInfoMoreList.value,
}); });
if ( if (
item.key === 'enterGroupConversation' item.key === 'enterGroupConversation'
|| item.key === 'enterC2CConversation' || item.key === 'enterC2CConversation'
) { ) {
emits('switchConversation', contactInfoData.value); emits('switchConversation', contactInfoData.value);
resetContactSearchingUIData(); resetContactSearchingUIData();
} }
}; };
const generateMoreInfo = async () => { const generateMoreInfo = async () => {
if (!isApplication.value) { if (!isApplication.value) {
if ( if (
(!isGroup.value && !isBothFriend.value && !isInBlackList.value) (!isGroup.value && !isBothFriend.value && !isInBlackList.value)
|| (isGroup.value || (isGroup.value
&& !isGroupMember.value && !isGroupMember.value
&& (contactInfoData.value as IGroupModel)?.type !== TUIChatEngine?.TYPES?.GRP_AVCHATROOM) && (contactInfoData.value as IGroupModel)?.type !== TUIChatEngine?.TYPES?.GRP_AVCHATROOM)
) { ) {
contactMoreInfoConfig.setWords.data = ''; contactMoreInfoConfig.setWords.data = '';
contactInfoMoreList.value.push(contactMoreInfoConfig.setWords); contactInfoMoreList.value.push(contactMoreInfoConfig.setWords);
} }
if (!isGroup.value && !isInBlackList.value) { if (!isGroup.value && !isInBlackList.value) {
contactMoreInfoConfig.setRemark.data contactMoreInfoConfig.setRemark.data
= (contactInfoData.value as Friend)?.remark || ''; = (contactInfoData.value as Friend)?.remark || '';
contactMoreInfoConfig.setRemark.editing = false; contactMoreInfoConfig.setRemark.editing = false;
contactInfoMoreList.value.push(contactMoreInfoConfig.setRemark); contactInfoMoreList.value.push(contactMoreInfoConfig.setRemark);
} }
if (!isGroup.value && (isBothFriend.value || isInBlackList.value)) { if (!isGroup.value && (isBothFriend.value || isInBlackList.value)) {
contactMoreInfoConfig.blackList.data = isInBlackList.value || false; contactMoreInfoConfig.blackList.data = isInBlackList.value || false;
contactInfoMoreList.value.push(contactMoreInfoConfig.blackList); contactInfoMoreList.value.push(contactMoreInfoConfig.blackList);
} }
} else { } else {
contactMoreInfoConfig.displayWords.data contactMoreInfoConfig.displayWords.data
= (contactInfoData.value as FriendApplication)?.wording || ''; = (contactInfoData.value as FriendApplication)?.wording || '';
contactInfoMoreList.value.push(contactMoreInfoConfig.displayWords); contactInfoMoreList.value.push(contactMoreInfoConfig.displayWords);
} }
}; };
const generateButton = () => { const generateButton = () => {
if (isInBlackList.value) { if (isInBlackList.value) {
return; return;
} }
if (isApplication.value) { if (isApplication.value) {
if ( if (
(contactInfoData.value as FriendApplication)?.type (contactInfoData.value as FriendApplication)?.type
=== TUIChatEngine?.TYPES?.SNS_APPLICATION_SENT_TO_ME === TUIChatEngine?.TYPES?.SNS_APPLICATION_SENT_TO_ME
) { ) {
contactInfoButtonList?.value?.push( contactInfoButtonList?.value?.push(
contactButtonConfig.refuseFriendApplication, contactButtonConfig.refuseFriendApplication,
); );
contactInfoButtonList?.value?.push( contactInfoButtonList?.value?.push(
contactButtonConfig.acceptFriendApplication, contactButtonConfig.acceptFriendApplication,
); );
} }
} else { } else {
if (isGroup.value && isGroupMember.value) { if (isGroup.value && isGroupMember.value) {
switch ((contactInfoData.value as IGroupModel)?.selfInfo?.role) { switch ((contactInfoData.value as IGroupModel)?.selfInfo?.role) {
case 'Owner': case 'Owner':
contactInfoButtonList?.value?.push(contactButtonConfig.dismissGroup); contactInfoButtonList?.value?.push(contactButtonConfig.dismissGroup);
break; break;
default: default:
contactInfoButtonList?.value?.push(contactButtonConfig.quitGroup); contactInfoButtonList?.value?.push(contactButtonConfig.quitGroup);
break; break;
} }
contactInfoButtonList?.value?.push( contactInfoButtonList?.value?.push(
contactButtonConfig.enterGroupConversation, contactButtonConfig.enterGroupConversation,
); );
} else if (!isGroup.value && isBothFriend.value) { } else if (!isGroup.value && isBothFriend.value) {
contactInfoButtonList?.value?.push(contactButtonConfig.deleteFriend); contactInfoButtonList?.value?.push(contactButtonConfig.deleteFriend);
contactInfoButtonList?.value?.push( contactInfoButtonList?.value?.push(
contactButtonConfig.enterC2CConversation, contactButtonConfig.enterC2CConversation,
); );
} else { } else {
if (isGroup.value) { if (isGroup.value) {
contactInfoButtonList?.value?.push( contactInfoButtonList?.value?.push(
(contactInfoData.value as IGroupModel)?.type === TUIChatEngine?.TYPES?.GRP_AVCHATROOM (contactInfoData.value as IGroupModel)?.type === TUIChatEngine?.TYPES?.GRP_AVCHATROOM
? contactButtonConfig.joinAVChatGroup ? contactButtonConfig.joinAVChatGroup
: contactButtonConfig.joinGroup, : contactButtonConfig.joinGroup,
); );
} else { } else {
contactInfoButtonList?.value?.push(contactButtonConfig.addFriend); contactInfoButtonList?.value?.push(contactButtonConfig.addFriend);
} }
} }
} }
}; };
function onUserBlacklistUpdated(userBlacklist: IBlackListUserItem[]) { function onUserBlacklistUpdated(userBlacklist: IBlackListUserItem[]) {
blackList.value = userBlacklist; blackList.value = userBlacklist;
} }
async function onCurrentContactInfoUpdated(contactInfo: IContactInfoType) { async function onCurrentContactInfoUpdated(contactInfo: IContactInfoType) {
if ( if (
contactInfoData.value contactInfoData.value
&& contactInfo && contactInfo
&& JSON.stringify(contactInfoData.value) === JSON.stringify(contactInfo) && JSON.stringify(contactInfoData.value) === JSON.stringify(contactInfo)
) { ) {
return; return;
} }
resetContactInfoUIData(); resetContactInfoUIData();
// deep clone // deep clone
contactInfoData.value = deepCopy(contactInfo) || {}; contactInfoData.value = deepCopy(contactInfo) || {};
if (!contactInfoData.value || Object.keys(contactInfoData.value)?.length === 0) { if (!contactInfoData.value || Object.keys(contactInfoData.value)?.length === 0) {
return; return;
} }
contactInfoBasicList.value = generateContactInfoBasic( contactInfoBasicList.value = generateContactInfoBasic(
contactInfoData.value, contactInfoData.value,
); );
isBothFriend.value = await isFriend(contactInfoData.value); isBothFriend.value = await isFriend(contactInfoData.value);
generateMoreInfo(); generateMoreInfo();
generateButton(); generateButton();
if (contactInfo.infoKeyList) { if (contactInfo.infoKeyList) {
contactInfoMoreList.value = contactInfo.infoKeyList.map((key: string) => { contactInfoMoreList.value = contactInfo.infoKeyList.map((key: string) => {
return (contactMoreInfoConfig as any)[key]; return (contactMoreInfoConfig as any)[key];
}); });
} }
if (contactInfo.btnKeyList) { if (contactInfo.btnKeyList) {
contactInfoButtonList.value = contactInfo.btnKeyList.map((key: string) => { contactInfoButtonList.value = contactInfo.btnKeyList.map((key: string) => {
return (contactButtonConfig as any)[key]; return (contactButtonConfig as any)[key];
}); });
} }
} }
</script> </script>
<style lang="scss" scoped src="./style/index.scss"></style> <style lang="scss" scoped src="./style/index.scss"></style>

View File

@ -1,138 +1,138 @@
<template> <template>
<SelectFriend v-if="isShowSelectFriend" /> <SelectFriend v-if="isShowSelectFriend" />
<div <div
v-else-if="isShowContactList" v-else-if="isShowContactList"
:class="['tui-contact', !isPC && 'tui-contact-h5']" :class="['tui-contact', !isPC && 'tui-contact-h5']"
> >
<div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}"> <div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}">
<!-- <ContactSearch /> --> <!-- <ContactSearch /> -->
<ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" /> <ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" />
</div> </div>
<div <div
v-if="isShowContactInfo" v-if="isShowContactInfo"
:class="['tui-contact-right', !isPC && 'tui-contact-h5-right']" :class="['tui-contact-right', !isPC && 'tui-contact-h5-right']"
:style="{height:ht+'px'}" :style="{height:ht+'px'}"
> >
<ContactInfo @switchConversation="switchConversation" /> <ContactInfo @switchConversation="switchConversation" />
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine'; import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
import { TUIGlobal } from '@tencentcloud/universal-api'; import { TUIGlobal } from '@tencentcloud/universal-api';
import { ref, watchEffect,defineProps } from '../../adapter-vue'; import { ref, watchEffect,defineProps } from '../../adapter-vue';
import { isPC, isUniFrameWork } from '../../utils/env'; import { isPC, isUniFrameWork } from '../../utils/env';
const ht = uni.getSystemInfoSync().windowHeight const ht = uni.getSystemInfoSync().windowHeight
import SelectFriend from './select-friend/index.vue'; import SelectFriend from './select-friend/index.vue';
import ContactSearch from './contact-search/index.vue'; import ContactSearch from './contact-search/index.vue';
import ContactList from './contact-list/index.vue'; import ContactList from './contact-list/index.vue';
import ContactInfo from './contact-info/index.vue'; import ContactInfo from './contact-info/index.vue';
const emits = defineEmits(['switchConversation']); const emits = defineEmits(['switchConversation']);
const props = defineProps({ const props = defineProps({
// web/h5 single page application display format, uniapp please ignore // web/h5 single page application display format, uniapp please ignore
displayType: { displayType: {
type: String, type: String,
default: 'contactList', // "contactList" / "selectFriend" default: 'contactList', // "contactList" / "selectFriend"
require: false, require: false,
}, },
stu: { stu: {
type: Number, // String, Number, Object type: Number, // String, Number, Object
require: true, require: true,
} }
}); });
const displayTypeRef = ref<string>(props.displayType || 'contactList'); const displayTypeRef = ref<string>(props.displayType || 'contactList');
const isShowSelectFriend = ref(false); const isShowSelectFriend = ref(false);
const isShowContactList = ref(true); const isShowContactList = ref(true);
const isShowContactInfo = ref(true); const isShowContactInfo = ref(true);
const isstu=ref(props.stu); const isstu=ref(props.stu);
watchEffect(() => { watchEffect(() => {
isShowContactList.value = props?.displayType !== 'selectFriend'; isShowContactList.value = props?.displayType !== 'selectFriend';
}); });
TUIStore.watch(StoreName.CUSTOM, { TUIStore.watch(StoreName.CUSTOM, {
isShowSelectFriendComponent: (data: any) => { isShowSelectFriendComponent: (data: any) => {
if (!isUniFrameWork && props?.displayType === 'selectFriend') { if (!isUniFrameWork && props?.displayType === 'selectFriend') {
isShowSelectFriend.value = data; isShowSelectFriend.value = data;
isShowContactList.value = false; isShowContactList.value = false;
return; return;
} }
if (data) { if (data) {
isShowSelectFriend.value = true; isShowSelectFriend.value = true;
if (isUniFrameWork) { if (isUniFrameWork) {
displayTypeRef.value = 'selectFriend'; displayTypeRef.value = 'selectFriend';
TUIGlobal?.hideTabBar(); TUIGlobal?.hideTabBar();
} }
} else { } else {
isShowSelectFriend.value = false; isShowSelectFriend.value = false;
if (isUniFrameWork) { if (isUniFrameWork) {
displayTypeRef.value = props.displayType; displayTypeRef.value = props.displayType;
TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ }); TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ });
} }
} }
}, },
currentContactInfo: (contactInfo: any) => { currentContactInfo: (contactInfo: any) => {
isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0); isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0);
}, },
}); });
const switchConversation = (data: any) => { const switchConversation = (data: any) => {
isUniFrameWork isUniFrameWork
&& TUIGlobal?.navigateTo({ && TUIGlobal?.navigateTo({
url: '/TUIKit/components/TUIChat/index', url: '/TUIKit/components/TUIChat/index',
}); });
emits('switchConversation', data); emits('switchConversation', data);
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../../assets/styles/common"; @import "../../assets/styles/common";
.tui-contact { .tui-contact {
width: 100%; width: 100%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
&-left { &-left {
min-width: 285px; min-width: 285px;
flex: 0 0 24%; flex: 0 0 24%;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
&-right { &-right {
border-left: 1px solid #f4f5f9; border-left: 1px solid #f4f5f9;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
} }
.tui-contact-h5 { .tui-contact-h5 {
position: relative; position: relative;
&-left, &-left,
&-right { &-right {
width: 100%; width: 100%;
height: 100%; height: 100%;
flex: 1; flex: 1;
} }
&-right { &-right {
position: absolute; position: absolute;
z-index: 100; z-index: 100;
} }
&-left { &-left {
&-list { &-list {
overflow-y: auto; overflow-y: auto;
} }
} }
} }
</style> </style>

View File

@ -1,141 +1,141 @@
<template> <template>
<SelectFriend v-if="isShowSelectFriend" /> <SelectFriend v-if="isShowSelectFriend" />
<div <div
v-else-if="isShowContactList" v-else-if="isShowContactList"
:class="['tui-contact', !isPC && 'tui-contact-h5']" :class="['tui-contact', !isPC && 'tui-contact-h5']"
> >
<div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}" > <div :class="['tui-contact-left', !isPC && 'tui-contact-h5-left']" :style="{height:ht+'px'}" >
<ContactSearch @cancel="cancel" /> <ContactSearch @cancel="cancel" />
<ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" /> <ContactList :class="['tui-contact-left-list', !isPC && 'tui-contact-h5-left-list']" />
</div> </div>
<div <div
v-if="isShowContactInfo" v-if="isShowContactInfo"
:class="['tui-contact-right', !isPC && 'tui-contact-h5-right']" :class="['tui-contact-right', !isPC && 'tui-contact-h5-right']"
:style="{height:ht+'px'}" :style="{height:ht+'px'}"
> >
<ContactInfo @switchConversation="switchConversation" /> <ContactInfo @switchConversation="switchConversation" />
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine'; import { TUIStore, StoreName } from '@tencentcloud/chat-uikit-engine';
import { TUIGlobal } from '@tencentcloud/universal-api'; import { TUIGlobal } from '@tencentcloud/universal-api';
import { ref, watchEffect,defineProps } from '../../adapter-vue'; import { ref, watchEffect,defineProps } from '../../adapter-vue';
import { isPC, isUniFrameWork } from '../../utils/env'; import { isPC, isUniFrameWork } from '../../utils/env';
import SelectFriend from './select-friend/index.vue'; import SelectFriend from './select-friend/index.vue';
import ContactSearch from './contact-search/index.vue'; import ContactSearch from './contact-search/index.vue';
import ContactList from './contact-list/indexsea.vue'; import ContactList from './contact-list/indexsea.vue';
import ContactInfo from './contact-info/index.vue'; import ContactInfo from './contact-info/index.vue';
const emits = defineEmits(['switchConversation']); const emits = defineEmits(['switchConversation']);
const ht = uni.getSystemInfoSync().windowHeight const ht = uni.getSystemInfoSync().windowHeight
const props = defineProps({ const props = defineProps({
// web/h5 single page application display format, uniapp please ignore // web/h5 single page application display format, uniapp please ignore
displayType: { displayType: {
type: String, type: String,
default: 'contactList', // "contactList" / "selectFriend" default: 'contactList', // "contactList" / "selectFriend"
require: false, require: false,
}, },
stu: { stu: {
type: Number, // String, Number, Object type: Number, // String, Number, Object
require: true, require: true,
} }
}); });
const cancel=(item)=>{ const cancel=(item)=>{
emits('switchConversation', item); emits('switchConversation', item);
} }
const displayTypeRef = ref<string>(props.displayType || 'contactList'); const displayTypeRef = ref<string>(props.displayType || 'contactList');
const isShowSelectFriend = ref(false); const isShowSelectFriend = ref(false);
const isShowContactList = ref(true); const isShowContactList = ref(true);
const isShowContactInfo = ref(true); const isShowContactInfo = ref(true);
const isstu=ref(props.stu); const isstu=ref(props.stu);
watchEffect(() => { watchEffect(() => {
isShowContactList.value = props?.displayType !== 'selectFriend'; isShowContactList.value = props?.displayType !== 'selectFriend';
}); });
TUIStore.watch(StoreName.CUSTOM, { TUIStore.watch(StoreName.CUSTOM, {
isShowSelectFriendComponent: (data: any) => { isShowSelectFriendComponent: (data: any) => {
if (!isUniFrameWork && props?.displayType === 'selectFriend') { if (!isUniFrameWork && props?.displayType === 'selectFriend') {
isShowSelectFriend.value = data; isShowSelectFriend.value = data;
isShowContactList.value = false; isShowContactList.value = false;
return; return;
} }
if (data) { if (data) {
isShowSelectFriend.value = true; isShowSelectFriend.value = true;
if (isUniFrameWork) { if (isUniFrameWork) {
displayTypeRef.value = 'selectFriend'; displayTypeRef.value = 'selectFriend';
TUIGlobal?.hideTabBar(); TUIGlobal?.hideTabBar();
} }
} else { } else {
isShowSelectFriend.value = false; isShowSelectFriend.value = false;
if (isUniFrameWork) { if (isUniFrameWork) {
displayTypeRef.value = props.displayType; displayTypeRef.value = props.displayType;
TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ }); TUIGlobal?.showTabBar()?.catch(() => { /* ignore */ });
} }
} }
}, },
currentContactInfo: (contactInfo: any) => { currentContactInfo: (contactInfo: any) => {
isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0); isShowContactInfo.value = isPC || (contactInfo && typeof contactInfo === 'object' && Object.keys(contactInfo)?.length > 0);
}, },
}); });
const switchConversation = (data: any) => { const switchConversation = (data: any) => {
isUniFrameWork isUniFrameWork
&& TUIGlobal?.navigateTo({ && TUIGlobal?.navigateTo({
url: '/TUIKit/components/TUIChat/index', url: '/TUIKit/components/TUIChat/index',
}); });
emits('switchConversation', data); emits('switchConversation', data);
}; };
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../../assets/styles/common"; @import "../../assets/styles/common";
.tui-contact { .tui-contact {
width: 100%; width: 100%;
height: 100%; height: 100%;
box-sizing: border-box; box-sizing: border-box;
display: flex; display: flex;
overflow: hidden; overflow: hidden;
&-left { &-left {
min-width: 285px; min-width: 285px;
flex: 0 0 24%; flex: 0 0 24%;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
&-right { &-right {
border-left: 1px solid #f4f5f9; border-left: 1px solid #f4f5f9;
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
} }
.tui-contact-h5 { .tui-contact-h5 {
position: relative; position: relative;
&-left, &-left,
&-right { &-right {
width: 100%; width: 100%;
height: 100%; height: 100%;
flex: 1; flex: 1;
} }
&-right { &-right {
position: absolute; position: absolute;
z-index: 100; z-index: 100;
} }
&-left { &-left {
&-list { &-list {
overflow-y: auto; overflow-y: auto;
} }
} }
} }
</style> </style>

View File

@ -1,340 +1,477 @@
/** /**
* 短视频相关API * 短视频相关API
*/ */
import { http, Method } from "@/utils/request.js"; import {
http,
import api from "@/config/api.js"; Method
} from "@/utils/request.js";
/** import api from "@/config/api.js";
* 短视频关注列表
*/
export function vlogDetail(vlogId,userId) { /**
let data = { * 根据昵称搜索用户
vlogId, */
userId export function vlogSearchUser({
} id,
return http.request({ nickname,
url: api.vlog + "/vlog/detail", page,
method: Method.GET, pageSize
needToken: true, }) {
params: data, return http.request({
}); url: api.vlog + "/userInfo/searchByNickname",
} method: Method.GET,
needToken: true,
/** params: {
* 短视频关注列表 id,
*/ nickname,
export function vlogFollowList(page, pageSize,myId) { page,
let data = { pageSize
page, },
pageSize, });
myId }
}
return http.request({
url: api.vlog + "/vlog/followList", /**
method: Method.GET, * 短视频详情
needToken: true, */
params: data, export function vlogDetail(vlogId, userId) {
}); let data = {
} vlogId,
userId
/** }
* 短视频列表-true return http.request({
*/ url: api.vlog + "/vlog/detail",
export function vlogList(page, pageSize,userId='',search='') { method: Method.GET,
let data = { needToken: true,
page, params: data,
pageSize, });
userId, }
search
} /**
return http.request({ * 短视频关注列表
url: api.vlog + "/vlog/indexList", */
method: Method.GET, export function vlogFollowList(page, pageSize, myId) {
needToken: false, let data = {
params: data, page,
}); pageSize,
} myId
}
/** return http.request({
* 短视频喜欢 url: api.vlog + "/vlog/followList",
*/ method: Method.GET,
export function vlogLike({userId,vlogId,vlogerId}) { needToken: true,
return http.request({ params: data,
url: api.vlog + "/vlog/like", });
method: Method.POST, }
needToken: true,
params: {userId,vlogId,vlogerId} /**
}); * 短视频列表-true
} */
export function vlogList(page, pageSize, userId = '', cityCode = '', search = '') {
/** let data = {
* 短视频不喜欢 page,
*/ pageSize,
export function vlogUnLike({userId,vlogId,vlogerId}) { userId,
return http.request({ cityCode,
url: api.vlog + "/vlog/unlike", search
method: Method.POST, }
needToken: true, return http.request({
params: {userId,vlogId,vlogerId} url: api.vlog + "/vlog/indexList",
}); method: Method.GET,
} needToken: false,
params: data,
/** });
* 短视频评论数量统计 }
*/
export function vlogComment(vlogId) { /**
return http.request({ * 短视频喜欢
url: api.vlog + "/comment/counts", */
method: Method.GET, export function vlogLike({
needToken: true, userId,
params: { vlogId }, vlogId,
}); vlogerId
} }) {
return http.request({
url: api.vlog + "/vlog/like",
method: Method.POST,
needToken: true,
params: {
/** userId,
* 短视频关注博主 vlogId,
*/ vlogerId
export function vlogFollow(myId,vlogerId) { }
return http.request({ });
url: api.vlog + "/fans/follow", }
method: Method.POST,
needToken: true, /**
params: {myId,vlogerId} * 短视频不喜欢
}); */
} export function vlogUnLike({
userId,
/** vlogId,
* 短视频查询当前点赞数 vlogerId
*/ }) {
export function vlogTotalLikedCounts(vlogId) { return http.request({
return http.request({ url: api.vlog + "/vlog/unlike",
url: api.vlog + "/vlog/totalLikedCounts", method: Method.POST,
method: Method.POST, needToken: true,
needToken: true, params: {
params: {vlogId} userId,
}); vlogId,
} vlogerId
}
/** });
* 查询用户信息 }
*/
export function vlogUserInfo(userId) { /**
return http.request({ * 短视频评论数量统计
url: api.vlog + "/userInfo/query", */
method: Method.GET, export function vlogComment(vlogId) {
needToken: true, return http.request({
params: { userId }, url: api.vlog + "/comment/counts",
}); method: Method.GET,
} needToken: true,
params: {
/** vlogId
* 查询我的公开视频 },
*/ });
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 vlogFollow(myId, vlogerId) {
* 查询我的私密视频 return http.request({
*/ url: api.vlog + "/fans/follow",
export function vlogMyPrivateList(page,pageSize,userId) { method: Method.POST,
return http.request({ needToken: true,
url: api.vlog + "/vlog/myPrivateList", params: {
method: Method.GET, myId,
needToken: true, vlogerId
params: { page,pageSize,userId }, }
}); });
} }
/** /**
* 查询我喜欢的视频 * 短视频查询当前点赞数
*/ */
export function vlogMyLikedList(page,pageSize,userId) { export function vlogTotalLikedCounts(vlogId) {
return http.request({ return http.request({
url: api.vlog + "/vlog/myLikedList", url: api.vlog + "/vlog/totalLikedCounts",
method: Method.GET, method: Method.POST,
needToken: true, needToken: true,
params: { page,pageSize,userId }, params: {
}); vlogId
} }
});
/** }
* 查询我喜欢的视频
*/ /**
export function vlogMeTag(path,page,pageSize,userId) { * 查询用户信息
return http.request({ */
url: api.vlog + "/vlog/"+path, export function vlogUserInfo(userId) {
method: Method.GET, return http.request({
needToken: true, url: api.vlog + "/userInfo/query",
params: { page,pageSize,userId }, method: Method.GET,
}); needToken: true,
} params: {
userId
/** },
* 视频评论数量 });
*/ }
export function vlogCommentCounts(vlogId) {
return http.request({ /**
url: api.vlog + "/comment/counts", * 查询我的公开视频
method: Method.GET, */
needToken: true, export function vlogMyPublicList(page, pageSize, userId) {
params: { vlogId }, return http.request({
}); url: api.vlog + "/vlog/myPublicList",
} method: Method.GET,
needToken: true,
/** params: {
* 视频评论不喜欢 page,
*/ pageSize,
export function vlogCommentUnLike(userId,commentId) { userId
return http.request({ },
url: api.vlog + "/comment/unlike", });
method: Method.POST, }
needToken: true,
params: {userId,commentId} /**
}); * 查询我的私密视频
} */
export function vlogMyPrivateList(page, pageSize, userId) {
/** return http.request({
* 视频评论喜欢 url: api.vlog + "/vlog/myPrivateList",
*/ method: Method.GET,
export function vlogCommentLike(userId,commentId) { needToken: true,
return http.request({ params: {
url: api.vlog + "/comment/like", page,
method: Method.POST, pageSize,
needToken: true, userId
params: {userId,commentId} },
}); });
} }
/** /**
* 视频评论删除 * 查询我喜欢的视频
*/ */
export function vlogCommentDelete(vlogId,commentUserId,commentId) { export function vlogMyLikedList(page, pageSize, userId) {
return http.request({ return http.request({
url: api.vlog + "/comment/delete", url: api.vlog + "/vlog/myLikedList",
method: Method.DELETE, method: Method.GET,
needToken: true, needToken: true,
params: {vlogId,commentUserId,commentId} params: {
}); page,
} pageSize,
userId
},
/** });
* 查询视频评论内容 }
*/
export function vlogCommentList(page,pageSize,vlogId,userId) { /**
return http.request({ * 查询我喜欢的视频
url: api.vlog + "/comment/list", */
method: Method.GET, export function vlogMeTag(path, page, pageSize, userId) {
needToken: true, return http.request({
params: { page,pageSize,vlogId,userId }, url: api.vlog + "/vlog/" + path,
}); method: Method.GET,
} needToken: true,
params: {
/** page,
* 发表评论 pageSize,
*/ userId
export function vlogCommentCreate(data) { },
return http.request({ });
url: api.vlog + "/comment/create", }
method: Method.POST,
needToken: true, /**
data * 视频评论数量
}); */
} export function vlogCommentCounts(vlogId) {
return http.request({
/** url: api.vlog + "/comment/counts",
* 将视频转为公开 method: Method.GET,
*/ needToken: true,
export function vlogChangeToPublic(userId,vlogId) { params: {
return http.request({ vlogId
url: api.vlog + "/vlog/changeToPublic", },
method: Method.POST, });
needToken: true, }
params:{userId,vlogId}
}); /**
} * 视频评论不喜欢
*/
/** export function vlogCommentUnLike(userId, commentId) {
* 将视频转为私密 return http.request({
*/ url: api.vlog + "/comment/unlike",
export function vlogChangeToPrivate(userId,vlogId) { method: Method.POST,
return http.request({ needToken: true,
url: api.vlog + "/vlog/changeToPrivate", params: {
method: Method.POST, userId,
needToken: true, commentId
params:{userId,vlogId} }
}); });
} }
/** /**
* 修改信息 * 视频评论喜欢
*/ */
export function vlogModifyUserInfo(data,type) { export function vlogCommentLike(userId, commentId) {
return http.request({ return http.request({
url: api.vlog + "/userInfo/modifyUserInfo?type="+type, url: api.vlog + "/comment/like",
method: Method.POST, method: Method.POST,
needToken: true, needToken: true,
data params: {
}); userId,
} commentId
}
});
/** }
* 取关
*/ /**
export function vlogFansCancel({myId,vlogerId}) { * 视频评论删除
return http.request({ */
url: api.vlog + "/fans/cancel", export function vlogCommentDelete(vlogId, commentUserId, commentId) {
method: Method.POST, return http.request({
needToken: true, url: api.vlog + "/comment/delete",
params:{myId,vlogerId} method: Method.DELETE,
}); needToken: true,
} params: {
/** vlogId,
* 关注 commentUserId,
*/ commentId
export function vlogFansFollow({myId,vlogerId}) { }
return http.request({ });
url: api.vlog + "/fans/follow", }
method: Method.POST,
needToken: true,
params:{myId,vlogerId} /**
}); * 查询视频评论内容
} */
export function vlogCommentList(page, pageSize, vlogId, userId) {
/** return http.request({
* 我的粉丝 url: api.vlog + "/comment/list",
*/ method: Method.GET,
export function vlogQueryMyFans({myId,page,pageSize}) { needToken: true,
return http.request({ params: {
url: api.vlog + "/fans/queryMyFans", page,
method: Method.GET, pageSize,
needToken: true, vlogId,
params:{myId,page,pageSize} userId
}); },
} });
}
/**
* 我的关注 /**
*/ * 发表评论
export function vlogQueryMyFollows({myId,page,pageSize}) { */
return http.request({ export function vlogCommentCreate(data) {
url: api.vlog + "/fans/queryMyFollows", return http.request({
method: Method.GET, url: api.vlog + "/comment/create",
needToken: true, method: Method.POST,
params:{myId,page,pageSize} 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
}
});
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,10 @@
const dev = { const dev = {
// common: "https://common-api.pickmall.cn", // common: "https://common-api.pickmall.cn",
// buyer: "https://buyer-api.pickmall.cn", // buyer: "https://buyer-api.pickmall.cn",
common: "http://192.168.1.211:8890", common: "http://192.168.1.211:8890",
buyer: "http://192.168.1.211:8888", buyer: "http://192.168.1.211:8888",
vlog: "http://192.168.1.211:8099", vlog: "http://192.168.1.211:8099",
web: "http://192.168.1.211:8099", web: "http://192.168.1.211:8099",
}; };
// 生产环境 // 生产环境
const prod = { const prod = {

View File

@ -1,6 +1,6 @@
{ {
"name" : "wzj4", "name" : "wzj4",
"appid" : "__UNI__1F0975C", "appid" : "__UNI__6DB512D",
"description" : "admin", "description" : "admin",
"versionName" : "4.0.0", "versionName" : "4.0.0",
"versionCode" : 4000049, "versionCode" : 4000049,
@ -9,8 +9,8 @@
"compatible" : { "compatible" : {
"ignoreVersion" : true //trueHBuilderX1.9.0 "ignoreVersion" : true //trueHBuilderX1.9.0
}, },
"nvueStyleCompiler" : "uni-app", "nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3, "compilerVersion" : 3,
/* 5+App */ /* 5+App */
"usingComponents" : true, "usingComponents" : true,
"splashscreen" : { "splashscreen" : {
@ -19,18 +19,17 @@
"autoclose" : true, "autoclose" : true,
"delay" : 0 "delay" : 0
}, },
"screenOrientation" : [ "portrait-primary" ], "screenOrientation" : [ "portrait-primary" ],
"modules" : { "modules" : {
"Payment" : {}, "Payment" : {},
"Share" : {}, "Share" : {},
"Fingerprint" : {},
"FaceID" : {},
"Geolocation" : {}, "Geolocation" : {},
"Maps" : {}, "Maps" : {},
"OAuth" : {}, "OAuth" : {},
"Camera" : {}, "Camera" : {},
"Barcode" : {}, "Barcode" : {},
"VideoPlayer" : {} "VideoPlayer" : {},
"Push" : {}
}, },
"error" : { "error" : {
/* 404*/ /* 404*/
@ -90,7 +89,7 @@
"payment" : { "payment" : {
"weixin" : { "weixin" : {
"__platform__" : [ "ios", "android" ], "__platform__" : [ "ios", "android" ],
"appid" : "wx32788b91bdb614c0", "appid" : "wxebcdaea31881caab",
"UniversalLinks" : "https://m-b2b2c.pickmall.cn/app/" "UniversalLinks" : "https://m-b2b2c.pickmall.cn/app/"
}, },
"alipay" : { "alipay" : {
@ -100,14 +99,14 @@
"ad" : {}, "ad" : {},
"share" : { "share" : {
"weixin" : { "weixin" : {
"appid" : "wx32788b91bdb614c0", "appid" : "wxebcdaea31881caab",
"UniversalLinks" : "https://m-b2b2c.pickmall.cn/app/" "UniversalLinks" : "https://m-b2b2c.pickmall.cn/app/"
} }
}, },
"oauth" : { "oauth" : {
"weixin" : { "weixin" : {
"appid" : "wx32788b91bdb614c0", "appid" : "wxebcdaea31881caab",
"appsecret" : "230233cef7520ee935bbecad372a370e", "appsecret" : "71826d76bad096ec5407897c6ed1391f",
"UniversalLinks" : "https://m-b2b2c.pickmall.cn/app/" "UniversalLinks" : "https://m-b2b2c.pickmall.cn/app/"
}, },
"apple" : {}, "apple" : {},
@ -120,6 +119,9 @@
"__platform__" : [ "ios", "android" ], "__platform__" : [ "ios", "android" ],
"appkey_ios" : "f463d3350efe63f8be5d9a62f24d0aab", "appkey_ios" : "f463d3350efe63f8be5d9a62f24d0aab",
"appkey_android" : "fb3f1ccb34616c70f068aa950f3e27df" "appkey_android" : "fb3f1ccb34616c70f068aa950f3e27df"
},
"system" : {
"__platform__" : [ "ios", "android" ]
} }
}, },
"maps" : { "maps" : {
@ -174,7 +176,8 @@
"xxhdpi" : "CustomStartPage/start-page.9.png" "xxhdpi" : "CustomStartPage/start-page.9.png"
} }
} }
} },
"nativePlugins" : {}
}, },
"permission" : { "permission" : {
"scope.userLocation" : { "scope.userLocation" : {

View 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"}}]}

View 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"}}

View File

@ -0,0 +1,5 @@
{
"VIVO_APPKEY": "ebe0d2ef18e69264e8ddfb48472cb3ec",
"VIVO_APPID": "105722088",
"HONOR_APPID": "104443878"
}

View File

@ -0,0 +1,6 @@
{
"developer_id":"109999867274",
"app_id":"104443878",
"package_name":"cn.net.wzj.mall",
"version":"1.0"
}

View File

@ -0,0 +1,3 @@
{
"businessID": "45148"
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,17 @@
//
// JPushModule.h
// UniPluginJPush
//
// Created by huangshuni on 2021/1/12.
//
#import <Foundation/Foundation.h>
#import "DCUniModule.h"
NS_ASSUME_NONNULL_BEGIN
@interface JPushModule : DCUniModule
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,23 @@
<?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>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTracking</key>
<false/>
<key>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
</dict>
</array>
</dict>
</plist>

View File

@ -0,0 +1,169 @@
{
"name": "JG-JPush",
"id": "JG-JPush",
"version": "1.2.5",
"description": "极光推送Hbuilder插件",
"_dp_type":"nativeplugin",
"_dp_nativeplugin":{
"ios": {
"deploymentTarget": "11.0",
"validArchitectures": [
"arm64"
],
"plugins": [{
"type": "module",
"name": "JG-JPush",
"class": "JPushModule"
}],
"hooksClass": "JPushProxy",
"integrateType": "framework",
"frameworks": [
"CFNetwork.framework",
"CoreFoundation.framework",
"CoreTelephony.framework",
"SystemConfiguration.framework",
"CoreGraphics.framework",
"Foundation.framework",
"UIKit.framework",
"Security.framework",
"libz.tbd",
"AdSupport.framework",
"UserNotifications.framework",
"libresolv.tbd",
"WebKit.framework",
"AppTrackingTransparency.framework",
"StoreKit.framework"
],
"resources": [
],
"capabilities": {
"entitlements": {
"aps-environment":"development"
}
},
"privacies": [
"NSLocationAlwaysAndWhenInUseUsageDescription",
"NSLocationAlwaysUsageDescription",
"NSLocationWhenInUseUsageDescription"
],
"parameters": {
"JPUSH_ISPRODUCTION_IOS": {
"des": "[iOS]是否是生产环境是填true不是填false或者不填",
"key": "JPush:ISPRODUCTION"
},
"JPUSH_ADVERTISINGID_IOS": {
"des": "[iOS]广告标识符IDFA如果不需要使用IDFA可不填",
"key": "JPush:ADVERTISINGID"
},
"JPUSH_DEFAULTINITJPUSH_IOS": {
"des": "[iOS]是否默认初始化是填true不是填false或者不填",
"key": "JPush:DEFAULTINITJPUSH"
}
}
},
"android": {
"plugins": [
{
"type": "module",
"name": "JG-JPush",
"class": "cn.jiguang.uniplugin_jpush.JPushModule"
}
],
"integrateType": "aar",
"minSdkVersion": "19",
"permissions": [
"${applicationId}.permission.JPUSH_MESSAGE",
"android.permission.INTERNET",
"android.permission.ACCESS_NETWORK_STATE",
"android.permission.POST_NOTIFICATIONS",
"com.huawei.android.launcher.permission.CHANGE_BADGE",
"com.vivo.notification.permission.BADGE_ICON",
"com.hihonor.android.launcher.permission.CHANGE_BADGE",
"android.permission.VIBRATE",
"android.permission.ACCESS_COARSE_LOCATION",
"android.permission.ACCESS_FINE_LOCATION",
"android.permission.ACCESS_BACKGROUND_LOCATION",
"android.permission.READ_PHONE_STATE",
"android.permission.QUERY_ALL_PACKAGES",
"android.permission.GET_TASKS",
"android.permission.ACCESS_WIFI_STATE",
"android.permission.WRITE_EXTERNAL_STORAGE",
"android.permission.READ_EXTERNAL_STORAGE",
"${applicationId}.permission.MIPUSH_RECEIVE",
"com.coloros.mcs.permission.RECIEVE_MCS_MESSAGE",
"com.heytap.mcs.permission.RECIEVE_MCS_MESSAGE"
],
"parameters": {
"JPUSH_OPPO_APPKEY": {
"des": "厂商OPPO-appkey,示例OP-12345678",
"key": "OPPO_APPKEY"
},
"JPUSH_OPPO_APPID":{
"des": "厂商OPPO-appId,示例OP-12345678",
"key": "OPPO_APPID"
},
"JPUSH_OPPO_APPSECRET":{
"des": "厂商OPPO-appSecret,示例OP-12345678",
"key": "OPPO_APPSECRET"
},
"JPUSH_VIVO_APPKEY":{
"des": "厂商VIVO-appkey,示例12345678",
"key": "com.vivo.push.api_key"
},
"JPUSH_VIVO_APPID":{
"des": "厂商VIVO-appId,示例12345678",
"key": "com.vivo.push.app_id"
},
"JPUSH_MEIZU_APPKEY":{
"des": "厂商MEIZU-appKey,示例MZ-12345678",
"key": "MEIZU_APPKEY"
},
"JPUSH_MEIZU_APPID":{
"des": "厂商MEIZU-appId,示例MZ-12345678",
"key": "MEIZU_APPID"
},
"JPUSH_XIAOMI_APPKEY":{
"des": "厂商XIAOMI-appKey,示例MI-12345678",
"key": "XIAOMI_APPKEY"
},
"JPUSH_XIAOMI_APPID":{
"des": "厂商XIAOMI-appId,示例MI-12345678",
"key": "XIAOMI_APPID"
},
"JPUSH_HUAWEI_APPID":{
"des": "厂商HUAWEI-appId,示例appid=12346578",
"key": "com.huawei.hms.client.appid"
},
"JPUSH_HONOR_APPID" : {
"des" : "厂商HONOR-appId,示例12346578",
"key" : "com.hihonor.push.app_id"
},
"JPUSH_NIO_APPID" : {
"des" : "厂商nio-appId,示例12346578",
"key" : "nio_push_app_id"
},
"JPUSH_GOOGLE_API_KEY" : {
"des" : "厂商google api_key,示例:g-12346578",
"key" : "google_api_key"
},
"JPUSH_GOOGLE_APP_ID" : {
"des" : "厂商google mobilesdk_app_id,示例g-12346578",
"key" : "google_app_id"
},
"JPUSH_GOOGLE_PROJECT_NUMBER" : {
"des" : "厂商google project_number,示例g-12346578",
"key" : "gcm_defaultSenderId"
},
"JPUSH_GOOGLE_PROJECT_ID" : {
"des" : "厂商google project_id ,示例g-12346578",
"key" : "project_id"
},
"JPUSH_GOOGLE_STORAGE_BUCKET" : {
"des" : "厂商google storage_bucket,示例g-12346578",
"key" : "google_storage_bucket"
}
}
}
}
}

4096
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
{ {
"dependencies": { "dependencies": {
"@dcloudio/uni-app": "^2.0.2-4050720250324001", "@dcloudio/uni-app": "^2.0.2-4050720250324001",
"@tencentcloud/chat-uikit-uniapp": "^2.4.3", "@tencentcloud/chat-uikit-uniapp": "^2.4.3",
"@vue/runtime-core": "^3.5.13", "@vue/runtime-core": "^3.5.13",
"unplugin-vue2-script-setup": "^0.11.4", "unplugin-vue2-script-setup": "^0.11.4",
"vue": "^3.2.0", "vue": "^3.2.0",
"ws": "^8.18.1" "ws": "^8.18.1"
} }
} }

View File

@ -489,14 +489,14 @@
"navigationBarBackgroundColor": "#181b27" "navigationBarBackgroundColor": "#181b27"
} }
}, },
// { {
// "path" : "pages/me/settings", "path": "pages/me/settings",
// "style" : { "style": {
// "navigationBarTitleText" : "设置", "navigationBarTitleText": "设置",
// "navigationBarTextStyle" : "white", "navigationBarTextStyle": "white",
// "navigationBarBackgroundColor" : "#181b27" "navigationBarBackgroundColor": "#181b27"
// } }
// }, },
{ {
"path": "pages/me/myFans", "path": "pages/me/myFans",
"style": { "style": {
@ -543,7 +543,22 @@
"navigationBarTitleText": "消息详情", "navigationBarTitleText": "消息详情",
"navigationBarTextStyle": "white", "navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#181b27" "navigationBarBackgroundColor": "#181b27"
}
},
{
"path": "pages/search/search",
"style": {
"app-plus": {
"titleNView": false //
}
}
},
{
"path": "pages/search/searchList",
"style": {
"app-plus": {
"titleNView": false //
}
} }
} }
], ],
@ -1267,27 +1282,25 @@
{ {
"path": "components/TUIChat/index", "path": "components/TUIChat/index",
"style": { "style": {
"navigationBarTitleText": "腾讯云 IM", "navigationBarTitleText": "腾讯云 IM",
"app-plus": { "app-plus": {
"softinputMode": "adjustResize", "softinputMode": "adjustResize",
"titleNView": { "titleNView": {
"buttons": [ "buttons": [{
{ "type": "menu"
"type": "menu" // "click": "handleMenuClick" //
// "click": "handleMenuClick" // }]
}
},
"h5": {
"titleNView": {
"buttons": [{
"type": "menu"
}]
} }
]
} }
},
"h5": {
"titleNView": {
"buttons": [{
"type": "menu"
}]
}
}
} }
}, },
// chat : // chat :
{ {
"path": "components/TUIChat/video-play", "path": "components/TUIChat/video-play",

View File

@ -121,7 +121,7 @@
<view class="vlog-list"> <view class="vlog-list">
<block v-for="(vlog, index) in vlogList" :key="index"> <block v-for="(vlog, index) in vlogList" :key="index">
<image class="vlog-cover" :src="vlog.cover" @click="goToVlog(vlog)" mode="aspectFill"></image> <image class="vlog-cover" :src="vlog.cover||vlog.firstFrameImg" @click="goToVlog(vlog)" mode="aspectFill"></image>
</block> </block>
</view> </view>
@ -230,8 +230,9 @@
if (result.data.status == 200) { if (result.data.status == 200) {
this.pageUserInfo = result.data.data; this.pageUserInfo = result.data.data;
storage.setVlogUserInfo(this.pageUserInfo) storage.setVlogUserInfo(this.pageUserInfo)
// 查询用户信息 // 查询用户信息
this.myList(0, 'myPublicList', true); this.switchTab(0)
// this.myList(0, 'myPublicList', true);
this.setBasicUserInfo(this.pageUserInfo); this.setBasicUserInfo(this.pageUserInfo);
} }
}, },
@ -355,14 +356,14 @@
goMyFans(userId) { goMyFans(userId) {
uni.navigateTo({ uni.navigateTo({
animationType: "fade-in", animationType: "fade-in",
url: "myFans?userId=" + userId, url: "myFans",
}); });
}, },
// 关注列表 // 关注列表
goMyFollows(userId) { goMyFollows(userId) {
uni.navigateTo({ uni.navigateTo({
animationType: "fade-in", animationType: "fade-in",
url: "myFollows?userId=" + userId, url: "myFollows",
}); });
}, },
}, },

View File

@ -2,7 +2,7 @@
<view class="mpage"> <view class="mpage">
<view class="line"></view> <view class="line"></view>
<scroll-view scroll-y="true" @scrolltolower="pagingFansList()"> <scroll-view scroll-y="true" @scrolltolower="pagingFansList()">
<view class="user-wrapper" v-for="(f, index) in fansList" :key="index"> <view class="user-wrapper" v-for="(f, index) in fansList" :key="f.fanId">
<view class="user-info" @click="goTovlogerInfo(f.fanId)"> <view class="user-info" @click="goTovlogerInfo(f.fanId)">
<image class="face" :src="f.face" /> <image class="face" :src="f.face" />
<text class="user-name"> <text class="user-name">
@ -10,29 +10,19 @@
</text> </text>
</view> </view>
<view v-if="isLogin && f.me" class="operator-wrapper"> <view v-if="!from">
<text class="operator-words" style="color: #ffffff">你</text> <view v-if="f.bothFriend==0" class="operator-wrapper">
</view> <text class="operator-words" style="color: #ef274d" @click="followMe(f.fanId)">
<view v-else-if="!isLogin || isLogin && !f.follow && !f.fan" class="operator-wrapper"> 回粉
<text class="operator-words" style="color: #ffffff" @click="followMe(f.fanId)"> </text>
关注 </view>
</text> <view v-if="f.bothFriend==1" class="operator-wrapper">
</view> <text class="operator-words" style="color: #ffffff" @click="cancelFollow(f.fanId)">
<view v-else-if="isLogin && !f.follow && f.fan" class="operator-wrapper"> 互粉
<text class="operator-words" style="color: #ffffff" @click="followMe(f.fanId)"> </text>
回粉 </view>
</text>
</view>
<view v-else-if="isLogin && f.follow && !f.fan" class="operator-wrapper">
<text class="operator-words" style="color: #ef274d" @click="cancelFollow(f.fanId)">
已关注
</text>
</view>
<view v-else-if="isLogin && f.follow && f.fan" class="operator-wrapper">
<text class="operator-words" style="color: #ef274d" @click="cancelFollow(f.fanId)">
互关
</text>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
@ -53,28 +43,28 @@
data() { data() {
return { return {
userId: "", userId: "",
currentUserId: "",
isLogin: false,
screenHeight: 0, screenHeight: 0,
page: 0, page: 0,
totalPage: 0, totalPage: 0,
fansList: [], fansList: [],
from:false
}; };
}, },
onLoad(param) { onLoad(param) {
var uinfo = storage.getVlogUserInfo() if(!isStrEmpty(param.userId)){
if (uinfo == null) { this.from = true
return this.userId = param.userId
}else{
var uinfo = storage.getVlogUserInfo()
this.userId = uinfo.id;
} }
this.isLogin = true;
this.currentUserId = uinfo.id
this.userId = param.userId;
this.queryMyFansList(0); this.queryMyFansList(0);
}, },
methods: { methods: {
goTovlogerInfo(vlogerId) { goTovlogerInfo(vlogerId) {
var id = storage.getVlogUserInfo().id
// 是否是当前登录的用户 // 是否是当前登录的用户
if (this.currentUserId == vlogerId) { if (id == vlogerId) {
uni.switchTab({ uni.switchTab({
url: "me", url: "me",
}); });
@ -91,15 +81,15 @@
for (let i = 0; i < fansList.length; i++) { for (let i = 0; i < fansList.length; i++) {
let fan = fansList[i]; let fan = fansList[i];
if (fan.fanId == vlogerId) { if (fan.fanId == vlogerId) {
fan.follow = status; fan.bothFriend = status;
fansList.splice(i, 1, fan); // fansList.splice(i, 1);
} }
} }
me.fansList = fansList; me.fansList = fansList;
}, },
async cancelFollow(vlogerId) { async cancelFollow(vlogerId) {
let me = this; let me = this;
let userId = storage.getVlogUserInfo().id let userId = me.userId
let data = { let data = {
myId: userId, myId: userId,
vlogerId vlogerId
@ -107,7 +97,7 @@
var result = await vlogFansCancel(data) var result = await vlogFansCancel(data)
console.log(result) console.log(result)
if (result.data.status == 200) { if (result.data.status == 200) {
me.reFreshList(vlogerId, false); me.reFreshList(vlogerId, 0);
} else { } else {
uni.showToast({ uni.showToast({
title: result.data.msg, title: result.data.msg,
@ -118,7 +108,7 @@
}, },
async followMe(vlogerId) { async followMe(vlogerId) {
let me = this; let me = this;
let userId = this.currentUserId; let userId = me.userId;
let data = { let data = {
myId: userId, myId: userId,
vlogerId vlogerId
@ -126,7 +116,7 @@
var result = await vlogFansFollow(data) var result = await vlogFansFollow(data)
console.log(result) console.log(result)
if (result.data.status == 200) { if (result.data.status == 200) {
me.reFreshList(vlogerId, true); me.reFreshList(vlogerId, 1);
} else { } else {
uni.showToast({ uni.showToast({
title: result.data.msg, title: result.data.msg,
@ -147,7 +137,8 @@
page: page, page: page,
pageSize: 10 pageSize: 10
} }
var result = await vlogQueryMyFans(data) var result = await vlogQueryMyFans(data)
console.log(result)
if (result.data.status == 200) { if (result.data.status == 200) {
let fansList = result.data.data.rows; let fansList = result.data.data.rows;
let totalPage = result.data.data.total; let totalPage = result.data.data.total;
@ -217,7 +208,8 @@
height: 120rpx; height: 120rpx;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center;
margin-top: 20rpx; margin-top: 20rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
@ -231,8 +223,8 @@
flex-direction: row; flex-direction: row;
justify-content: center; justify-content: center;
background-color: #ef274d; background-color: #ef274d;
border-radius: 20rpx; border-radius: 20rpx;
align-self: center; align-items: center;
border-width: 2rpx; border-width: 2rpx;
border-color: #ef274d; border-color: #ef274d;
background-color: #181b27; background-color: #181b27;

View File

@ -2,7 +2,7 @@
<view class="mpage"> <view class="mpage">
<view class="line"></view> <view class="line"></view>
<scroll-view scroll-y="true" @scrolltolower="pagingFollowsList"> <scroll-view scroll-y="true" @scrolltolower="pagingFollowsList">
<view class="user-wrapper" v-for="(f, index) in followsList" :key="index"> <view class="user-wrapper" v-for="(f, index) in followsList" :key="f.vlogerId">
<view class="user-info" @click="goTovlogerInfo(f.vlogerId)"> <view class="user-info" @click="goTovlogerInfo(f.vlogerId)">
<image class="face" :src="f.face" /> <image class="face" :src="f.face" />
<text class="user-name"> <text class="user-name">
@ -10,64 +10,59 @@
</text> </text>
</view> </view>
<view v-if="f.me" class="operator-wrapper"> <view v-if="!from">
<text class="operator-words" style="color: #ffffff">你</text> <view v-if="f.bothFriend==0" class="operator-wrapper">
</view> <text class="operator-words" style="color: #ef274d" @click="cancelFollow(f.vlogerId)">
<view v-else-if="!f.follow" class="operator-wrapper"> 已关注
<text class="operator-words" style="color: #ffffff" @click="followMe(f.vlogerId)"> </text>
关注 </view>
</text> <view v-if="f.bothFriend==1" class="operator-wrapper">
</view> <text class="operator-words" style="color: #ffffff" @click="cancelFollow(f.vlogerId)">
<view v-else-if="f.follow && !f.fan" class="operator-wrapper"> 互关
<text class="operator-words" style="color: #ef274d" @click="cancelFollow(f.vlogerId)"> </text>
已关注 </view>
</text>
</view>
<view v-else-if="f.follow && f.fan" class="operator-wrapper">
<text class="operator-words" style="color: #ef274d" @click="cancelFollow(f.vlogerId)">
互关
</text>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
</template> </template>
<script> <script>
import storage from "@/utils/storage.js"; //缓存 import storage from "@/utils/storage.js"; //缓存
import { import {
vlogFansCancel, vlogFansCancel,
vlogFansFollow, vlogFansFollow,
vlogQueryMyFollows vlogQueryMyFollows
} from "@/api/vlog" } from "@/api/vlog"
import { import {
isStrEmpty isStrEmpty
} from '@/utils/tools.js' } from '@/utils/tools.js'
let system = uni.getSystemInfoSync(); let system = uni.getSystemInfoSync();
export default { export default {
data() { data() {
return { return {
userId: "", userId: "",
currentUserId: "",
screenHeight: 0, screenHeight: 0,
page: 0, page: 0,
totalPage: 0, totalPage: 0,
followsList: [], followsList: [],
from: false
}; };
}, },
onLoad(param) { onLoad(param) {
var uinfo = storage.getVlogUserInfo() if (!isStrEmpty(param.userId)) {
if (uinfo==null) { this.from = true
return this.userId = param.userId
} } else {
this.currentUserId = uinfo.id var uinfo = storage.getVlogUserInfo()
this.userId = param.userId; this.userId = uinfo.id;
}
this.queryMyFollowList(0); this.queryMyFollowList(0);
}, },
methods: { methods: {
goTovlogerInfo(vlogerId) { goTovlogerInfo(vlogerId) {
// 是否是当前登录的用户 var id = storage.getVlogUserInfo().id
if (this.currentUserId == vlogerId) { if (id == vlogerId) {
uni.switchTab({ uni.switchTab({
url: "me", url: "me",
}); });
@ -84,69 +79,67 @@
for (let i = 0; i < followsList.length; i++) { for (let i = 0; i < followsList.length; i++) {
let vloger = followsList[i]; let vloger = followsList[i];
if (vloger.vlogerId == vlogerId) { if (vloger.vlogerId == vlogerId) {
vloger.follow = status; vloger.bothFriend = status;
followsList.splice(i, 1, vloger); followsList.splice(i, 1);
} }
} }
me.followsList = followsList; me.followsList = followsList;
}, },
async cancelFollow(vlogerId) { async cancelFollow(vlogerId) {
let me = this; let me = this;
let userId = this.currentUserId; let userId = this.userId;
var data ={ var data = {
myId: userId, myId: userId,
vlogerId vlogerId
} }
var result = await vlogFansCancel(data) var result = await vlogFansCancel(data)
console.log(result) console.log(result)
if (result.data.status == 200) { if (result.data.status == 200) {
me.reFreshList(vlogerId, false); me.reFreshList(vlogerId, 0);
} else { } else {
uni.showToast({ uni.showToast({
title: result.data.msg, title: result.data.msg,
icon: "none", icon: "none",
duration: 3000, duration: 3000,
}); });
} }
}, },
async followMe(vlogerId) { async followMe(vlogerId) {
let me = this; let me = this;
let userId = this.currentUserId; let userId = this.userId;
let data = { let data = {
myId: userId, myId: userId,
vlogerId vlogerId
} }
var result = await vlogFansFollow(data) var result = await vlogFansFollow(data)
console.log(result) console.log(result)
if (result.data.status == 200) { if (result.data.status == 200) {
me.reFreshList(vlogerId, true); me.reFreshList(vlogerId, true);
} else { } else {
uni.showToast({ uni.showToast({
title: result.data.msg, title: result.data.msg,
icon: "none", icon: "none",
duration: 3000, duration: 3000,
}); });
} }
}, },
async queryMyFollowList(page) { async queryMyFollowList(page) {
let me = this; let me = this;
page = page + 1; page = page + 1;
let userId = me.userId; let userId = me.userId;
let currentUserId = this.currentUserId; var data = {
var data = { myId: userId,
myId:userId, page: page,
// vlogerId: userId, pageSize: 10
// currentUserId: currentUserId, }
page: page, var result = await vlogQueryMyFollows(data)
pageSize: 10 if (result.data.status == 200) {
} let followsList = result.data.data.rows;
var result = await vlogQueryMyFollows(data) let totalPage = result.data.data.total;
if (result.data.status == 200) { me.followsList = me.followsList.concat(followsList);
let followsList = result.data.data.rows; console.log(me.followsList)
let totalPage = result.data.data.total; me.page = page;
me.followsList = me.followsList.concat(followsList); me.totalPage = totalPage;
me.page = page;
me.totalPage = totalPage;
} }
}, },
@ -157,8 +150,8 @@
} }
this.queryMyFollowList(this.page); this.queryMyFollowList(this.page);
}, },
}, }
}; }
</script> </script>
<style scoped> <style scoped>
@ -206,7 +199,7 @@
justify-content: space-between; justify-content: space-between;
margin-top: 20rpx; margin-top: 20rpx;
margin-bottom: 20rpx; margin-bottom: 20rpx;
align-items: center;
} }

227
pages/me/settings.vue Executable file
View File

@ -0,0 +1,227 @@
<template>
<view class="page">
<!-- <view class="line"></view> -->
<scroll-view scroll-y="true">
<view
style="
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 20rpx;
">
<view
style="
display: flex;
flex-direction: column;
justify-content: center;
">
<image
src="/static/imooc/lee.jpeg"
mode="widthFix"
class="fengjianyingyue"
style="align-self: center"></image>
<image
src="/static/imooc/fengjianyingyue.png"
mode="widthFix"
class="fengjianyingyue-name"
style="align-self: center"></image>
</view>
<view>
<text class="introduce">
物流科技公司部门经理近10年开发和技术管理经验主要从事后端技术和架构领域有丰富的电商平台与物流平台核心系统的架构设计和开发经验
拥有丰富的大型项目开发经验授课风格诙谐幽默讲解到位细致
</text>
<text class="introduce">
近20万的学生学习人数学生入职公司有
百度云盘阿里腾讯云字节跳动金山网易OPPO新浪微博华为货拉拉58同城海信蘑菇街金蝶
</text>
</view>
</view>
<view
style="
display: flex;
flex-direction: row;
justify-content: center;
margin-top: 20rpx;
">
<image
src="/static/imooc/course-javaarchitect.png"
mode="widthFix"
class="course"
style="width: 380rpx"></image>
</view>
<view
style="
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 20rpx;
padding-left: 30rpx;
padding-right: 30rpx;
">
<image
src="/static/imooc/course-pm.png"
mode="widthFix"
class="course"
style=""></image>
<image
src="/static/imooc/course-springcloud.png"
mode="widthFix"
class="course"
style=""></image>
</view>
<view
style="
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 20rpx;
padding-left: 30rpx;
padding-right: 30rpx;
">
<image
src="/static/imooc/course-netty.png"
mode="widthFix"
class="course"
style=""></image>
<image
src="/static/imooc/course-zookeeper.png"
mode="widthFix"
class="course"
style=""></image>
</view>
<!-- <view style="display: flex;flex-direction: row;justify-content: center;margin-top: 20rpx;">
<image src="/static/imooc/lee-qrcode.png" mode="widthFix" class="course" style="width: 380rpx;"></image>
</view> -->
<view
:class="{ logout: !logoutTouched, 'logout-touched': logoutTouched }"
@touchstart="touchstartLogout"
@touchend="touchendLogout"
@click="logout"
style="
margin-top: 20rpx;
padding-left: 30rpx;
padding-right: 30rpx;
width: 750rpx;
height: 120rpx;
display: flex;
flex-direction: row;
justify-content: center;
">
<text style="color: #ffffff; align-self: center; font-size: 15px">
退出登录
</text>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
logoutTouched: false,
};
},
onLoad() {},
methods: {
touchstartLogout() {
this.logoutTouched = true;
},
touchendLogout() {
this.logoutTouched = false;
},
logout() {
// let userId = getApp().getUserInfoSession().id;
// uni.request({
// method: "GET",
// url: serverUrl + "/passport/logout?userId=" + userId,
// success(result) {
// let status = result.data.status;
// if (status == 211) {
// app.clearUserInfo();
// uni.showToast({
// title: result.data.msg,
// duration: 3000
// })
// // list
// // uni.setStorageSync("needRefreshIndexVlogList", "1");
// // uni.switchTab({
// // url: "../index/index"
// // })
// uni.reLaunch({
// url: "../index/index",
// });
// }
// },
// });
},
},
};
</script>
<style>
.page {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #181b27;
}
.line {
height: 1rpx;
background-color: #393a41;
width: 750rpx;
}
.place-box {
background-color: #4a4c52;
}
.place-box-touched {
background-color: #6d6b6b;
}
.right-arrow {
width: 32rpx;
height: 32rpx;
margin-left: 20rpx;
}
.logout {
background-color: #4a4c52;
}
.logout-touched {
background-color: #6d6b6b;
}
.fengjianyingyue {
width: 250rpx;
border-width: 1rpx;
border-color: #ffffff;
border-radius: 10rpx;
}
.fengjianyingyue-name {
width: 200rpx;
margin-top: 26rpx;
opacity: 0.8;
}
.introduce {
color: #f1f1f1;
font-size: 26rpx;
font-weight: 300;
width: 440rpx;
}
.course {
width: 330rpx;
border-radius: 5px;
}
</style>

687
pages/me/vlogerInfo.nvue Executable file
View File

@ -0,0 +1,687 @@
<template>
<view class="page">
<scroll-view
class="isLogin-info-wrapper"
:style="{ height: screenHeight + 'px' }"
scroll-y="true"
@scrolltolower="loadMore">
<image class="mybg" :src="pageUserInfo.bgImg" mode="aspectFill" />
<view class="header" :style="{ marginTop: statusBarHeight + 'px' }">
<image
class="header-right-search"
src="../../static/images/icon-back.png"
@click="back()" />
</view>
<view class="my-info-wrapper">
<view class="my-info">
<image :src="pageUserInfo.face" mode="aspectFill" class="my-face" />
<view class="info-wrapper">
<text class="nickname">
{{ pageUserInfo.nickname }}
</text>
<view class="tiktok-num-wrapper">
<text class="tiktok-num">视频号:</text>
<text class="tiktok-num">
{{ pageUserInfo.imoocNum }}
</text>
</view>
<view class="location">
<text class="location-text">所在地:</text>
<text class="location-text">
{{ pageUserInfo.city == "" ? "中国" : "" + pageUserInfo.city
}}{{
pageUserInfo.district == "" ? "" : "·" + pageUserInfo.district
}}
</text>
</view>
<view class="sex-wrapper">
<view class="constellation">
<image
class="sex-img"
v-if="pageUserInfo.sex == 1"
src="/static/images/icon-sex-boy.png" />
<image
class="sex-img"
v-if="pageUserInfo.sex == 0"
src="/static/images/icon-sex-girl.png" />
<image
class="sex-img"
v-if="pageUserInfo.sex == 2"
src="/static/images/icon-sex-secret.png" />
<text class="astro">{{ astro }}座</text>
</view>
<view class="animal">
<text class="animal-text">
{{ animal }}
</text>
</view>
</view>
</view>
</view>
</view>
<text class="desc">
{{ pageUserInfo.description }}
</text>
<view class="bottom-wrapper">
<view class="bottom">
<view class="bottom-item" @click="goMyFollows(pageUserInfo.id)">
<text class="item-num">
{{ getGraceNumber(pageUserInfo.myFollowsCounts) }}
</text>
<text class="item-text">关注</text>
</view>
<view class="bottom-item" @click="goMyFans(pageUserInfo.id)">
<text class="item-num">
{{ getGraceNumber(pageUserInfo.myFansCounts) }}
</text>
<text class="item-text">粉丝</text>
</view>
<view class="bottom-item">
<text class="item-num">
{{ getGraceNumber(pageUserInfo.totalLikeMeCounts) }}
</text>
<text class="item-text">获赞</text>
</view>
</view>
<view class="edit">
<view
v-if="isFollow && !isFan"
@click="cancelFollow()"
class="follow-btn">
<text class="follow-text">已关注</text>
</view>
<view
v-if="isFollow && isFan"
@click="cancelFollow()"
class="follow-btn">
<text class="follow-text">相互关注</text>
</view>
<view
v-if="!isFollow"
@click="followMe()"
class="follow-btn"
style="background-color: #ef274d">
<text class="follow-text">关注我</text>
</view>
</view>
</view>
<view class="tab-wrapper">
<view class="tab-item" @click="switchTab(0)">
<text class="tab-normal" :class="{ 'tab-selected': currentTab == 0 }">
作品
</text>
<view v-if="currentTab == 0" class="selected-tab"></view>
</view>
<!-- <view class="tab-item" @click="switchTab(1)">
<text class="tab-normal" :class="{ 'tab-selected': currentTab == 1 }">
私密
</text>
<view v-if="currentTab == 1" class="selected-tab"></view>
</view> -->
<view class="tab-item" @click="switchTab(1)">
<text class="tab-normal" :class="{ 'tab-selected': currentTab == 1 }">
赞过
</text>
<view v-if="currentTab == 1" class="selected-tab"></view>
</view>
</view>
<view class="vlog-list">
<block v-for="(vlog, index) in vlogList" :key="index">
<image
class="vlog-cover"
:src="vlog.cover||vlog.firstFrameImg"
@click="goToVlog(vlog)"
mode="aspectFill"></image>
</block>
</view>
<view v-if="vlogList.length == 0" class="empty">
<text class="empty-text">~ 空空如也 ~</text>
</view>
<view v-if="vlogList.length > 0" class="not-empty">
<text class="not-empty-text">~ 没有更多了 ~</text>
</view>
</scroll-view>
</view>
</template>
<script>
let system = uni.getSystemInfoSync();
import * as filters from "@/utils/filters.js"
import api from "@/config/api.js";
import storage from "@/utils/storage.js"; //缓存
import {
vlogUserInfo,
vlogQueryDoIFollowVloger,
vlogMyPublicList,
vlogMyPrivateList,
vlogMyLikedList,
vlogMeTag,
vlogFansCancel,
vlogFansFollow
} from "@/api/vlog"
import {
getAstro,
getAnimal,
dateFormat,
graceNumber,
isStrEmpty
} from '@/utils/tools.js'
export default {
data() {
return {
pageUserInfo: {
id: "",
mobile: "",
nickname: "",
imoocNum: "",
face: "",
birthday: "1998-12-31T16:00:00.000+0000",
country: "",
province: "",
city: "",
district: "",
description: "",
myFollowsCounts: 0,
myFansCounts: 0,
totalLikeMeCounts: 0
},
userPageId: "",
astro: "",
animal: "",
loginWords: "请登录",
statusBarHeight: 0,
screenHeight: 0,
screenHeightUnLogin: 0,
currentTab: 0,
isFollow: false,
isFan: false,
isAndroid: uni.getSystemInfoSync().platform == "android",
page: 0,
totalpage: 0,
vlogList: [],
};
},
async onLoad(params) {
this.statusBarHeight = system.statusBarHeight;
let screenHeight = system.safeArea.bottom + 50;
this.screenHeight = screenHeight;
let screenHeightUnLogin = system.safeArea.bottom;
this.screenHeightUnLogin = screenHeightUnLogin;
let me = this;
// 从视频页面, 点击用户头像传递过来的id
let userPageId = params.userPageId;
if (isStrEmpty(userPageId)) {
uni.showToast({
title: "出错啦~",
icon: " none",
duration: 2000,
});
settimeout(() => {
uni.navigateBack({
delta: 1,
});
}, 1500);
}
me.userPageId = userPageId;
var result = await vlogUserInfo(userPageId)
console.log(result)
if (result.data.status == 200) {
me.pageUserInfo = result.data.data;
me.setBasicUserInfo(me.pageUserInfo);
} else {
uni.showToast({
title: result.data.msg,
icon: "none",
duration: 3000,
});
}
// this.switchTab(0);
this.myList(0, 'myPublicList', true);
let myUserId = "";
let info = storage.getVlogUserInfo()
if (info!=null) {
myUserId = info.id;
}
if (!isStrEmpty(myUserId)) {
// 查询我是否关注博主
var result = await vlogQueryDoIFollowVloger({myId:myUserId,vlogerId:userPageId})
console.log(result)
if (result.data.status == 200) {
me.isFollow = result.data.data;
// me.isFan = result.data.data;
} else {
uni.showToast({
title: result.data.msg,
icon: "none",
duration: 3000,
});
}
// 查询博主是否关注我
var result2 = await vlogQueryDoIFollowVloger({myId:userPageId,vlogerId:myUserId})
if (result2.data.status == 200) {
me.isFan = result2.data.data;
} else {
uni.showToast({
title: result2.data.msg,
icon: "none",
duration: 3000,
});
}
}
},
methods: {
setBasicUserInfo(myUserInfo) {
// 根据生日判断星座
let birthday = myUserInfo.birthday;
let birth = dateFormat("YYYY-mm-dd", new Date(birthday));
let birthArr = birth.split("-");
let year = birthArr[0];
let month = birthArr[1];
let day = birthArr[2];
let astro = getAstro(month, day);
this.astro = astro;
// 根据生日判断生肖
let animal = getAnimal(year);
this.animal = animal;
},
switchTab(index) {
this.currentTab = index;
if (index == 0) {
this.page = 0;
this.toalPage = 0;
this.myList(0, 'myPublicList', true);
} else if (index == 1) {
this.page = 0;
this.toalPage = 0;
this.myList(0, 'myLikedList', true);
}
},
loadMore() {
if (this.page >= this.toalPage) {
return;
} else {
this.myList(this.page);
}
},
async myList(page, requrl, init = false) {
let me = this;
page = page + 1;
me.page = page;
let userId = me.userPageId;;
var result = await vlogMeTag(requrl, page, 20, userId)
if (result.data.status == 200) {
let vlogList = result.data.data.rows;
console.log(vlogList)
let toalPage = result.data.data.total;
if (init) {
me.vlogList = vlogList
} else {
me.vlogList = me.vlogList.concat(vlogList);
}
me.page = page;
me.toalPage = toalPage;
}
},
back() {
uni.navigateBack({
delta: 1,
});
},
async cancelFollow() {
let me = this;
let vlogerId = me.userPageId;
let userId = storage.getVlogUserInfo().id;
var result = await vlogFansCancel({myId:userId,vlogerId:vlogerId})
if (result.data.status == 200) {
me.isFollow = false;
// uni.setStorageSync("justCancelVlogerId", vlogerId);
// 刷新当前页的粉丝数
let pendingInfo = me.pageUserInfo;
me.pageUserInfo.myFansCounts = pendingInfo.myFansCounts - 1;
} else {
uni.showToast({
title: result.data.msg,
icon: "none",
duration: 3000,
});
}
},
async followMe() {
let me = this;
let myUserInfo = storage.getVlogUserInfo();
let vlogerId = me.userPageId;
let userId = myUserInfo.id;
var result = await vlogFansFollow({myId:userId,vlogerId:vlogerId})
if (result.data.status == 200) {
me.isFollow = true;
// uni.setStorageSync("justFollowVlogerId", vlogerId);
// 刷新当前页的粉丝数
let pendingInfo = me.pageUserInfo;
me.pageUserInfo.myFansCounts = pendingInfo.myFansCounts + 1;
} else {
uni.showToast({
title: result.data.msg,
icon: "none",
duration: 3000,
});
}
},
// 把超过1000或10000的数字调整, 比如1.3k/6.8w
getGraceNumber(num) {
return graceNumber(num);
},
goToVlog(vlog) {
let vlogId = vlog.id ? vlog.id : vlog.vlogId;
// uni.navigateTo({
// url: "../vlog/vlog?type=mine&isNeedPage=1&vlogId=" + vlogId,
// });
uni.navigateTo({
url: "/pages/me/vlog?vlogId=" + vlogId,
});
},
goMyFans(userId) {
uni.navigateTo({
animationType: "fade-in",
url: "myFans?userId=" + userId,
});
},
goMyFollows(userId) {
uni.navigateTo({
animationType: "fade-in",
url: "myFollows?userId=" + userId,
});
},
},
};
</script>
<style lang="scss">
.page {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: #000000;
.isLogin-info-wrapper {
.header {
position: absolute;
left: 0;
right: 0;
flex-direction: row;
height: 100rpx;
line-height: 100rpx;
align-items: center;
padding-left: 40rpx;
padding-right: 40rpx;
.header-right-search {
width: 40rpx;
height: 40rpx;
opacity: 0.8;
}
}
.mybg {
width: 750rpx;
height: 750rpx;
box-shadow: inset 0 -150px 180px #313030;
}
.my-info-wrapper {
position: relative;
left: 30rpx;
top: -560rpx;
display: flex;
flex-direction: column;
width: 1000rpx;
.my-info {
display: flex;
flex-direction: row;
.my-face {
width: 200rpx;
height: 200rpx;
border-radius: 100rpx;
border-width: 1px;
border-color: #f1f1f1;
}
.info-wrapper {
margin-left: 30rpx;
padding-top: 20rpx;
width: 500rpx;
.nickname {
font-size: 20px;
color: #ffffff;
font-weight: 600;
}
.tiktok-num-wrapper {
display: flex;
flex-direction: row;
.tiktok-num {
font-size: 10px;
color: #ffffff;
font-weight: 300;
}
}
.location {
display: flex;
flex-direction: row;
height: 20px;
margin-top: 2px;
font-size: 1px;
.location-text {
line-height: 20px;
color: #ffffff;
font-size: 10px;
font-weight: 300;
}
}
.sex-wrapper {
display: flex;
flex-direction: row;
margin-top: 10rpx;
.constellation {
display: flex;
flex-direction: row;
justify-content: center;
background-color: #000000;
opacity: 0.5;
width: 130rpx;
height: 40rpx;
border-radius: 10px;
.sex-img {
width: 22rpx;
height: 22rpx;
align-self: center;
}
.astro {
font-size: 10px;
color: #ffffff;
line-height: 20px;
font-weight: bold;
margin-left: 6rpx;
align-self: center;
}
}
.animal {
margin-left: 10rpx;
display: flex;
flex-direction: row;
justify-content: center;
background-color: #000000;
opacity: 0.5;
width: 60rpx;
height: 40rpx;
border-radius: 10px;
.animal-text {
font-size: 10px;
color: #ffffff;
line-height: 20px;
font-weight: bold;
align-self: center;
}
}
}
}
}
}
.desc {
position: relative;
top: -520rpx;
color: #ffffff;
font-size: 14px;
margin: 0 30rpx;
}
.bottom-wrapper {
position: relative;
top: -510rpx;
display: flex;
flex-direction: row;
justify-content: space-between;
.bottom {
display: flex;
flex-direction: row;
.bottom-item {
margin-left: 30rpx;
display: flex;
flex-direction: column;
justify-content: center;
.item-num {
color: #ffffff;
font-size: 14px;
font-weight: bold;
align-self: center;
}
.item-text {
color: #ffffff;
font-size: 12px;
font-weight: 300;
align-self: center;
}
}
}
.edit {
display: flex;
flex-direction: row;
justify-content: center;
margin-right: 30rpx;
.follow-btn {
margin-right: 20rpx;
border-width: 1px;
border-color: #ffffff;
width: 200rpx;
height: 66rpx;
background-color: #545456;
opacity: 0.8;
border-radius: 40rpx;
display: flex;
flex-direction: row;
justify-content: center;
align-self: center;
.follow-text {
font-size: 13px;
color: #ffffff;
font-weight: 500;
align-self: center;
}
}
}
}
.tab-wrapper {
position: relative;
top: -480rpx;
height: 40px;
background-color: #171825;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-top: 3px;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
.tab-item {
width: 250rpx;
align-self: center;
.tab-normal {
font-size: 18px;
font-weight: 500;
align-self: center;
color: #808080;
}
.tab-selected {
color: #ffffff;
}
.selected-tab {
margin-top: 5px;
height: 5rpx;
width: 250rpx;
border-radius: 6rpx;
background-color: #ef274d;
}
}
}
.vlog-list {
position: relative;
top: -480rpx;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
background-color: #000000;
.vlog-cover {
align-self: center;
width: 248rpx;
height: 360rpx;
border-width: 1rpx;
}
}
.empty {
background-color: #000000;
width: 750rpx;
height: 300rpx;
display: flex;
flex-direction: row;
justify-content: center;
position: relative;
top: -480rpx;
.empty-text {
color: #ffffff;
font-size: 14px;
margin-top: 200rpx;
}
}
.not-empty {
width: 750rpx;
display: flex;
flex-direction: row;
justify-content: center;
position: relative;
top: -260rpx;
.not-empty-text {
color: #ffffff;
font-size: 14px;
}
}
}
}
</style>

View File

@ -464,8 +464,13 @@ export default {
}); });
return; return;
} else { } else {
storage.setAccessToken(res.data.result.accessToken); var infoData = res.data.result;
storage.setRefreshToken(res.data.result.refreshToken); storage.setAccessToken(infoData.accessToken);
storage.setRefreshToken(infoData.refreshToken);
const vlogInfo = JSON.parse(infoData.tikUser);
// vlogtokenvlog
storage.setVlogToken(vlogInfo.userToken);
storage.setVlogUserInfo(vlogInfo);
// //
uni.showToast({ uni.showToast({
title: "第三方登录成功!", title: "第三方登录成功!",

View File

@ -1,375 +1,418 @@
<template> <template>
<scroll-view class="prpage" scroll-y="true"> <scroll-view
<view class="line"></view> class="prpage"
<!-- 进度条 --> scroll-y="true"
<view class="progress" v-if="percentCompleted != 100"> >
<progress :percent="percentCompleted" stroke-width="3" activeColor="#ef274d" backgroundColor="#F1F1F1" /> <view class="line"></view>
<text class="progress-text">视频上传中,请耐心等待~~</text> <!-- 进度条 -->
<image class="progress-img" mode="aspectFit" src="/static/images/loading-4.gif" /> <view
</view> class="progress"
v-if="percentCompleted != 100"
<!-- 发布主体内容 --> >
<view class="main-body" v-if="percentCompleted == 100"> <progress
<image class="main-body-img-m" v-if="tempCover" :src="tempCover" mode="widthFix" /> :percent="percentCompleted"
<image class="main-body-img-m" v-if="!tempCover" src='/static/images/loading-4.gif' mode="aspectFit" /> stroke-width="3"
<view class="main-body-content"> activeColor="#ef274d"
<view class="preplay-wrapper" @click="preview" @touchstart="touchstartPreplay" backgroundColor="#F1F1F1"
@touchend="touchendPreplay"> />
<image class="preplay-icon" src="/static/images/btn-play.png" /> <text class="progress-text">视频上传中,请耐心等待~~</text>
<text class="preplay-text">预览视频</text> <image
</view> class="progress-img"
<view class="choose-cover" @click="chooseCover"> mode="aspectFit"
<text class="choose-cover-text">选择封面</text> src="/static/images/loading-4.gif"
</view> />
</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="{ <view
'btn-publish': !publishTouched, class="main-body"
'btn-publish-touched': publishTouched, v-if="percentCompleted == 100"
}" @touchstart="touchstartPublish" @touchend="touchendPublish" @click="doPublich"> >
<text class="btn-text">发布视频</text> <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>
</view> <textarea
</scroll-view> class="vlog-content"
</template> placeholder-style="color: #9798a0;"
placeholder="添加合适的描述内容~"
<script> :value="title"
import storage from "@/utils/storage.js"; //缓存 :model="title"
// import { maxlength="60"
// graceNumber @input="typingContent"
// } from '@/utils/tools.js' confirm-type="done"
import api from "@/config/api.js"; ></textarea>
export default { <view
data() { class="mbtn"
return { :class="{
publishTouched: false, 'btn-publish': !publishTouched,
preplayTouched: false, 'btn-publish-touched': publishTouched
tempFilePath: "", }"
videoUrl: "", @touchstart="touchstartPublish"
tempCover: "", // 视频封面 @touchend="touchendPublish"
title: "", @click="doPublich"
width: 0, >
height: 0, <text class="btn-text">发布视频</text>
percentCompleted: 0, // 进度 </view>
}; </view>
}, </scroll-view>
onLoad(params) { </template>
let me = this;
let vlogInfo = storage.getVlogUserInfo() <script>
// 上个页面传过来的文件事件对象, 其中包含了相册中选择的视频内容 import storage from '@/utils/storage.js'; //缓存
let fileObjectEvent = JSON.parse(params.fileObjectEvent); // import {
let times = new Date().getTime(); // graceNumber
var userId = vlogInfo.id; // } from '@/utils/tools.js'
let nickname = vlogInfo.nickname; import api from '@/config/api.js';
export default {
let serverUrl = api.vlog; data() {
const uploadTask = uni.uploadFile({ return {
filePath: fileObjectEvent.tempFilePath, publishTouched: false,
url: serverUrl + "/upload", preplayTouched: false,
name: 'file', tempFilePath: '',
formData: { videoUrl: '',
filetype: 'video' tempCover: '', // 视频封面
}, title: '',
header: { width: 0,
headerUserId: userId, height: 0,
headerUserToken: storage.getVlogToken() percentCompleted: 0 // 进度
}, };
success: (f) => { },
console.log(f) onLoad(params) {
let jsondata = f.data let me = this;
let data = JSON.parse(jsondata) let vlogInfo = storage.getVlogUserInfo();
let videoUrl = data.data; // 上个页面传过来的文件事件对象, 其中包含了相册中选择的视频内容
me.videoUrl = videoUrl; let fileObjectEvent = JSON.parse(params.fileObjectEvent);
me.width = fileObjectEvent.width; let times = new Date().getTime();
me.height = fileObjectEvent.height; var userId = vlogInfo.id;
} let nickname = vlogInfo.nickname;
})
let serverUrl = api.vlog;
uploadTask.onProgressUpdate((res) => { const uploadTask = uni.uploadFile({
console.log('上传进度' + res.progress); filePath: fileObjectEvent.tempFilePath,
// console.log('已经上传的数据长度' + res.totalBytesSent); url: serverUrl + '/upload',
// console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend); name: 'file',
// 显示进度 formData: {
// let percentCompleted = Math.round( filetype: 'video'
// (res.progress * 100) / res.total },
// ); header: {
me.percentCompleted = res.progress headerUserId: userId,
}) headerUserToken: storage.getVlogToken()
}, },
methods: { success: (f) => {
typingContent(e) { console.log(f);
let event = e; let jsondata = f.data;
this.title = e.detail.value; let data = JSON.parse(jsondata);
}, let videoUrl = data.data;
doPublich() { me.videoUrl = videoUrl;
if (this.title.length < 5) { me.width = fileObjectEvent.width;
uni.showToast({ me.height = fileObjectEvent.height;
title: "请输入5个字以上的标题", }
icon: "none", });
});
return; uploadTask.onProgressUpdate((res) => {
} console.log('上传进度' + res.progress);
let me = this; // console.log('已经上传的数据长度' + res.totalBytesSent);
let vlogInfo = storage.getVlogUserInfo() // console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
let userId = vlogInfo.id; // 显示进度
let vlog = { // let percentCompleted = Math.round(
vlogerId: userId, // (res.progress * 100) / res.total
url: me.videoUrl, // );
cover: me.tempCover || '', me.percentCompleted = res.progress;
title: me.title, });
width: me.width, },
height: me.height, methods: {
}; typingContent(e) {
let event = e;
// 发布视频 this.title = e.detail.value;
let serverUrl = api.vlog },
uni.request({ doPublich() {
method: "POST", if (this.title.length < 5) {
header: { uni.showToast({
headerUserId: userId, title: '请输入5个字以上的标题',
headerUserToken: storage.getVlogToken(), icon: 'none'
}, });
url: serverUrl + "/vlog/publish", return;
data: vlog, }
success(result) { let me = this;
if (result.data.status == 200) { let vlogInfo = storage.getVlogUserInfo();
uni.showToast({ let userId = vlogInfo.id;
title: result.data.msg, let vlog = {
icon: "none", vlogerId: userId,
duration: 2000, url: me.videoUrl,
}); cover: me.tempCover || '',
title: me.title,
setTimeout(() => { width: me.width,
uni.switchTab({ height: me.height,
url: "/pages/tabbar/user/my", cityCode: storage.getCityCode()
}); };
}, 2000);
} else { // 发布视频
uni.showToast({ let serverUrl = api.vlog;
title: result.data.msg, uni.request({
icon: "none", method: 'POST',
duration: 3000, header: {
}); headerUserId: userId,
} headerUserToken: storage.getVlogToken()
}, },
}); url: serverUrl + '/vlog/publish',
}, data: vlog,
success(result) {
preview() { if (result.data.status == 200) {
uni.navigateTo({ uni.showToast({
url: "/pages/publish/preview?videoUrl=" + title: result.data.msg,
this.videoUrl + icon: 'none',
"&width=" + duration: 2000
this.width + });
"&height=" +
this.height, setTimeout(() => {
animationType: "slide-in-bottom", uni.switchTab({
animationDuration: 500, url: '/pages/me/me'
}); });
}, }, 2000);
} else {
touchstartPreplay() { uni.showToast({
this.preplayTouched = true; title: result.data.msg,
}, icon: 'none',
duration: 3000
touchendPreplay() { });
this.preplayTouched = false; }
}, }
});
touchstartPublish() { },
this.publishTouched = true;
}, preview() {
uni.navigateTo({
touchendPublish() { url: '/pages/publish/preview?videoUrl=' + this.videoUrl + '&width=' + this.width + '&height=' + this.height,
this.publishTouched = false; animationType: 'slide-in-bottom',
}, animationDuration: 500
});
chooseCover() { },
let me = this;
let vlogInfo = storage.getVlogUserInfo() touchstartPreplay() {
let userId = vlogInfo.id; this.preplayTouched = true;
uni.chooseImage({ },
count: 1,
sizeType: "original", touchendPreplay() {
sourceType: ["album"], this.preplayTouched = false;
success(e) { },
me.tempCover = e.tempFilePaths[0]; //先在本地回显
// 上传封面 touchstartPublish() {
let serverUrl = api.vlog; this.publishTouched = true;
uni.uploadFile({ },
filePath: e.tempFilePaths[0],
url: serverUrl + "/upload", touchendPublish() {
formData: { this.publishTouched = false;
filetype: 'video' },
},
header: { chooseCover() {
headerUserId: userId, let me = this;
headerUserToken: storage.getVlogToken(), let vlogInfo = storage.getVlogUserInfo();
}, let userId = vlogInfo.id;
name: "file", uni.chooseImage({
success(result) { count: 1,
let res = JSON.parse(result.data); sizeType: 'original',
console.log(res) sourceType: ['album'],
if (res.status == 200) { success(e) {
let imageUrl = res.data; me.tempCover = e.tempFilePaths[0]; //先在本地回显
me.tempCover = imageUrl; // 上传封面
uni.showToast({ let serverUrl = api.vlog;
title: res.msg, uni.uploadFile({
duration: 2000, filePath: e.tempFilePaths[0],
}); url: serverUrl + '/upload',
} else { formData: {
uni.showToast({ filetype: 'video'
title: res.msg, },
icon: "none", header: {
duration: 3000, 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;
</script> uni.showToast({
title: res.msg,
<style scoped> duration: 2000
.prpage { });
position: absolute; } else {
left: 0; uni.showToast({
right: 0; title: res.msg,
top: 0; icon: 'none',
bottom: 0; duration: 3000
background-color: #181b27; });
} }
}
});
.main-body-img-m { }
min-height: 400rpx; });
/* width: 750rpx; */ }
border: 2rpx solid #545456; }
border-radius: 20rpx; };
align-items: center; </script>
}
<style scoped>
.choose-cover-text { .prpage {
color: #ffffff; position: absolute;
font-size: 28rpx; left: 0;
align-items: center; right: 0;
} top: 0;
bottom: 0;
.choose-cover { background-color: #181b27;
display: flex; }
flex-direction: column;
justify-content: center; .main-body-img-m {
margin-left: 100rpx; min-height: 400rpx;
margin-top: 10px; /* width: 750rpx; */
width: 200rpx; border: 2rpx solid #545456;
height: 100rpx; border-radius: 20rpx;
position: relative; align-items: center;
}
} .choose-cover-text {
color: #ffffff;
.preplay-icon { font-size: 28rpx;
width: 22rpx; align-items: center;
height: 22rpx; }
align-items: center;
} .choose-cover {
display: flex;
.preplay-text { flex-direction: column;
color: #e6e6e6; justify-content: center;
font-size: 28rpx; margin-left: 100rpx;
align-items: center; margin-top: 10px;
margin-left: 15rpx; width: 200rpx;
} height: 100rpx;
position: relative;
.preplay-wrapper { }
display: flex;
flex-direction: row; .preplay-icon {
justify-content: center; width: 22rpx;
padding: 6rpx 16rpx; height: 22rpx;
width: 200rpx; align-items: center;
} }
.main-body-content { .preplay-text {
/* display: flex; */ color: #e6e6e6;
flex-direction: row; font-size: 28rpx;
justify-content: flex-start; align-items: center;
margin-left: 15rpx;
} }
.vlog-content { .preplay-wrapper {
margin-top: 30rpx; display: flex;
height: 200rpx; flex-direction: row;
color: #000000; justify-content: center;
font-size: 16px; padding: 6rpx 16rpx;
background-color: #ffffff; width: 200rpx;
padding-left: 20rpx; }
padding-top: 20rpx;
padding-right: 20rpx; .main-body-content {
padding-bottom: 20rpx; /* display: flex; */
border-radius: 20rpx; flex-direction: row;
} justify-content: flex-start;
}
.btn-text {
color: #e6e6e6; .vlog-content {
font-size: 36rpx; margin-top: 30rpx;
align-items: center; height: 200rpx;
font-weight: 500; color: #000000;
} font-size: 16px;
background-color: #ffffff;
.mbtn { padding-left: 20rpx;
margin-top: 30rpx; padding-top: 20rpx;
height: 90rpx; padding-right: 20rpx;
/* display: flex; */ padding-bottom: 20rpx;
justify-content: center; border-radius: 20rpx;
align-items: center; }
border-radius: 40rpx;
border: transparent; .btn-text {
} color: #e6e6e6;
font-size: 36rpx;
.btn-publish { align-items: center;
background-color: #ef274d; font-weight: 500;
overflow: hidden; }
}
.mbtn {
.btn-publish-touched { margin-top: 30rpx;
background-color: #de6981; height: 90rpx;
overflow: hidden; /* display: flex; */
} justify-content: center;
align-items: center;
border-radius: 40rpx;
.main-body { border: transparent;
margin-top: 20rpx; }
padding: 0 20rpx;
} .btn-publish {
background-color: #ef274d;
.line { overflow: hidden;
height: 1rpx; }
background-color: #393a41;
width: 750rpx; .btn-publish-touched {
} background-color: #de6981;
overflow: hidden;
.progress { }
margin-top: 60rpx;
display: flex; .main-body {
flex-direction: column; margin-top: 20rpx;
justify-content: center; padding: 0 20rpx;
width: 750rpx; }
}
.line {
.progress-text { height: 1rpx;
color: #f1f1f1; background-color: #393a41;
font-size: 32rpx; width: 750rpx;
text-align: center; }
margin-top: 40rpx;
} .progress {
margin-top: 60rpx;
.progress-img { display: flex;
width: 600rpx; flex-direction: column;
height: 600rpx; justify-content: center;
align-items: center; width: 750rpx;
} }
</style>
.progress-text {
color: #f1f1f1;
font-size: 32rpx;
text-align: center;
margin-top: 40rpx;
}
.progress-img {
width: 600rpx;
height: 600rpx;
align-items: center;
}
</style>

296
pages/search/search.vue Executable file
View 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>

399
pages/search/searchList.vue Executable file
View 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
View 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';
}
},
// 1000100001.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
View 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
View 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
View 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>

View File

@ -1,24 +1,27 @@
<template> <template>
<div style="height: 100%"> <div style="height: 100%">
<div class="jolkp"> <div class="jolkp">
<div class="fan" :style="{ marginRight: statue == 0 ? '50%' : '50%' }"> <div
<div class="fan"
@click="hui(0)" :style="{ marginRight: statue == 0 ? '50%' : '50%' }"
:style="{ marginTop: '35px', color: '#fff' }" >
v-if="statue == 1 || 6" <div
> @click="hui(0)"
< :style="{ marginTop: '35px', color: '#fff' }"
</div> v-if="statue == 1 || 6"
</div> >
<!-- <TUIContact v-else-if="statue==1" :stu="2" /> --> <
<div </div>
@click="hui(6)" </div>
class="jolkp_z" <!-- <TUIContact v-else-if="statue==1" :stu="2" /> -->
v-if="statue == 0 || 6" <div
:style="{ marginTop: '40px' }" @click="hui(6)"
> class="jolkp_z"
<div class="tiole">{{ tole }}</div> v-if="statue == 0 || 6"
</div> :style="{ marginTop: '40px' }"
>
<div class="tiole">{{ tole }}</div>
</div>
<div <div
@click="hui(1)" @click="hui(1)"
@ -83,10 +86,13 @@
</div> </div>
</scroll-view> </scroll-view>
<!-- </div> --> <!-- </div> -->
<!-- 会话 --> <!-- 会话 -->
<TUIConversation style="height: 100%" v-else /> <TUIConversation
</div> style="height: 100%"
v-else
/>
</div>
</template> </template>
<script> <script>
@ -157,7 +163,52 @@ export default {
userSig: par.userSig, userSig: par.userSig,
useUploadPlugin: true, // If you need to send rich media messages, please set to true. useUploadPlugin: true, // If you need to send rich media messages, please set to true.
framework: `vue${vueVersion}`, // framework used vue2 / vue3 framework: `vue${vueVersion}`, // framework used vue2 / vue3
}); }).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 { } else {
// 200 // 200
uni.navigateTo({ uni.navigateTo({
@ -318,152 +369,152 @@ uni-page-body,
html, html,
body, body,
page { page {
width: 100% !important; width: 100% !important;
height: 100% !important; height: 100% !important;
overflow: hidden; overflow: hidden;
} }
.jolkp { .jolkp {
height: 66px; height: 66px;
display: flex; display: flex;
font-size: 15px; font-size: 15px;
justify-content: end; justify-content: end;
/* 设置背景图 */ /* 设置背景图 */
background-image: url("@/static/im/Rectangle.png"); background-image: url('@/static/im/Rectangle.png');
/* 让背景图覆盖整个元素 */ /* 让背景图覆盖整个元素 */
background-size: cover; background-size: cover;
/* 背景图不重复 */ /* 背景图不重复 */
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.jolkp_l { .jolkp_l {
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
background-image: url("@/static/im/Frame.png"); background-image: url('@/static/im/Frame.png');
/* 让背景图覆盖整个元素 */ /* 让背景图覆盖整个元素 */
background-size: cover; background-size: cover;
/* 背景图不重复 */ /* 背景图不重复 */
background-repeat: no-repeat; background-repeat: no-repeat;
margin-top: 35px; margin-top: 35px;
margin-right: 10px; margin-right: 10px;
} }
.jolkp_h { .jolkp_h {
width: 2rem; width: 2rem;
height: 2rem; height: 2rem;
background-image: url("@/static/im/user.png"); background-image: url('@/static/im/user.png');
/* 让背景图覆盖整个元素 */ /* 让背景图覆盖整个元素 */
background-size: cover; background-size: cover;
/* 背景图不重复 */ /* 背景图不重复 */
background-repeat: no-repeat; background-repeat: no-repeat;
margin-top: 35px; margin-top: 35px;
margin-right: 20px; margin-right: 20px;
} }
.jolkp_z { .jolkp_z {
width: 2rem; width: 2rem;
height: 1.5rem; height: 1.5rem;
background-image: url("@/static/im/znx.png"); background-image: url('@/static/im/znx.png');
/* 让背景图覆盖整个元素 */ /* 让背景图覆盖整个元素 */
background-size: cover; background-size: cover;
/* 背景图不重复 */ /* 背景图不重复 */
background-size: 100% 100%; background-size: 100% 100%;
margin-top: 35px; margin-top: 35px;
margin-right: 20px; margin-right: 20px;
} }
.tiole { .tiole {
margin-top: -10px; margin-top: -10px;
margin-left: 105%; margin-left: 105%;
color: #fff; color: #fff;
font-size: 14px; font-size: 14px;
} }
.popup { .popup {
position: absolute; position: absolute;
top: 65px; top: 65px;
/* 调整弹出框的位置 */ /* 调整弹出框的位置 */
right: 5px; right: 5px;
background-color: #fff; background-color: #fff;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 4px; border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
z-index: 3; z-index: 3;
} }
.popup ul { .popup ul {
list-style-type: none; list-style-type: none;
padding: 0; padding: 0;
margin: 0; margin: 0;
} }
.popup li { .popup li {
padding: 10px 20px; padding: 10px 20px;
cursor: pointer; cursor: pointer;
} }
.popup li:hover { .popup li:hover {
background-color: #f0f0f0; background-color: #f0f0f0;
} }
.fan { .fan {
width: 10%; width: 10%;
height: "100%"; height: '100%';
font-size: 18px; font-size: 18px;
display: flex; display: flex;
padding: 5px; padding: 5px;
} }
@media screen and (device-width: 393px) and (device-height: 851px) and (-webkit-device-pixel-ratio: 3) { @media screen and (device-width: 393px) and (device-height: 851px) and (-webkit-device-pixel-ratio: 3) {
.fan { .fan {
margin-right: 56% !important; margin-right: 56% !important;
width: 10%; width: 10%;
height: "100%"; height: '100%';
font-size: 18px; font-size: 18px;
display: flex; display: flex;
margin-top: 85%; margin-top: 85%;
padding: 5px; padding: 5px;
} }
} }
.three { .three {
width: 100%; width: 100%;
height: 10%; height: 10%;
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
background: rgb(255, 255, 255); background: rgb(255, 255, 255);
} }
.con { .con {
width: 100%; width: 100%;
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.three_div1 { .three_div1 {
height: 3rem; height: 3rem;
width: 40%; width: 40%;
background-image: url("@/static/im/kf.png"); background-image: url('@/static/im/kf.png');
background-size: 100% 100%; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: end; justify-content: end;
} }
.three_div2 { .three_div2 {
width: 40%; width: 40%;
height: 3rem; height: 3rem;
background-image: url("@/static/im/hy.png"); background-image: url('@/static/im/hy.png');
background-size: 100% 100%; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
width: 40%; width: 40%;
} }
.three_div3 { .three_div3 {
height: 3rem; height: 3rem;
background-image: url("@/static/im/da.png"); background-image: url('@/static/im/da.png');
background-size: 100% 100%; background-size: 100% 100%;
background-repeat: no-repeat; background-repeat: no-repeat;
width: 40%; width: 40%;
} }
.tui-conversation-item { .tui-conversation-item {
/* height: 10%; */ /* height: 10%; */
@ -479,39 +530,39 @@ page {
position: relative; position: relative;
} }
.content { .content {
display: flex; display: flex;
flex: 1; flex: 1;
padding-left: 8px; padding-left: 8px;
justify-content: end; justify-content: end;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden; overflow: hidden;
} }
.left { .left {
position: relative; position: relative;
width: 36px; width: 36px;
height: 36px; height: 36px;
} }
.znx { .znx {
max-height: 100vh; max-height: 100vh;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
overflow-y: auto; overflow-y: auto;
} }
.delete-button { .delete-button {
position: absolute; position: absolute;
right: 0; right: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
width: 100px; width: 100px;
background-color: red; background-color: red;
color: white; color: white;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
} }
</style> </style>

File diff suppressed because it is too large Load Diff

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