Browse Source

feat: add typescript support

dev
zyronon 1 year ago
parent
commit
e3e09ebdd3
  1. 110
      src/pages/home/Report.vue
  2. 1003
      src/pages/home/SearchPage.vue
  3. 78
      src/pages/home/SubmitReport.vue
  4. 15
      src/pages/login/Help.vue
  5. 136
      src/pages/login/Login.vue
  6. 140
      src/pages/login/VerificationCode.vue
  7. 208
      src/pages/me/MyMusic.vue
  8. 27
      src/pages/me/MyRequestUpdate.vue
  9. 94
      src/pages/me/RequestUpdate.vue
  10. 49
      src/pages/message/RedPacketDetail.vue
  11. 71
      src/pages/message/SetRemark.vue
  12. 412
      src/pages/message/Share2Friend.vue
  13. 691
      src/pages/message/chat/Chat.vue
  14. 140
      src/pages/message/chat/ChatDetail.vue
  15. 92
      src/pages/message/notice/LiveNotice.vue
  16. 127
      src/pages/message/notice/MoneyNotice.vue
  17. 114
      src/pages/message/notice/NoticeSetting.vue
  18. 156
      src/pages/message/notice/TaskNotice.vue
  19. 2
      src/pages/other/VideoDetail.vue
  20. 32
      src/pages/people/AddressList.vue
  21. 19
      src/pages/people/FaceToFace.vue
  22. 206
      src/pages/people/FindAcquaintance.vue
  23. 113
      src/pages/people/FollowAndFans.vue
  24. 15
      src/pages/people/Scan.vue
  25. 1
      src/router/routes.ts
  26. 2
      src/utils/index.jsx

110
src/pages/home/Report.vue

@ -3,9 +3,9 @@
<BaseHeader backMode="light"> <BaseHeader backMode="light">
<template v-slot:center> <template v-slot:center>
<span class="f16"> <span class="f16">
<template v-if="mode === 'video'">视频</template> <template v-if="data.mode === 'video'">视频</template>
<template v-if="mode === 'music'">音乐</template> <template v-if="data.mode === 'music'">音乐</template>
<template v-if="mode === 'chat'">私信</template>举报</span <template v-if="data.mode === 'chat'">私信</template>举报</span
> >
</template> </template>
</BaseHeader> </BaseHeader>
@ -13,43 +13,55 @@
<div class="title"> <div class="title">
<span>内容违规</span> <span>内容违规</span>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '色情低俗', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '色情低俗', mode: data.mode })">
<span>色情低俗</span> <span>色情低俗</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '时政不实信息', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '时政不实信息', mode: data.mode })"
>
<span>时政不实信息</span> <span>时政不实信息</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '违法犯罪', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '违法犯罪', mode: data.mode })">
<span>违法犯罪</span> <span>违法犯罪</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '垃圾广告、售卖假货等', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '垃圾广告、售卖假货等', mode: data.mode })"
>
<span>垃圾广告售卖假货等</span> <span>垃圾广告售卖假货等</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '造谣传播', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '造谣传播', mode: data.mode })">
<span>造谣传播</span> <span>造谣传播</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '涉嫌欺诈', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '涉嫌欺诈', mode: data.mode })">
<span>涉嫌欺诈</span> <span>涉嫌欺诈</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '侮辱漫骂', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '侮辱漫骂', mode: data.mode })">
<span>侮辱漫骂</span> <span>侮辱漫骂</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '危险行为', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '危险行为', mode: data.mode })">
<span>危险行为</span> <span>危险行为</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '涉嫌非法集资', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '涉嫌非法集资', mode: data.mode })"
>
<span>涉嫌非法集资</span> <span>涉嫌非法集资</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '价值观导向不良', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '价值观导向不良', mode: data.mode })"
>
<span>价值观导向不良</span> <span>价值观导向不良</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
@ -61,20 +73,26 @@
<div <div
class="row" class="row"
@click=" @click="
$nav('/home/submit-report', { nav('/home/submit-report', {
type: '侵犯名誉、隐私、肖像权等', type: '侵犯名誉、隐私、肖像权等',
mode mode: data.mode
}) })
" "
> >
<span>侵犯名誉隐私肖像权等</span> <span>侵犯名誉隐私肖像权等</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '内容盗用本人作品', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '内容盗用本人作品', mode: data.mode })"
>
<span>内容盗用本人作品</span> <span>内容盗用本人作品</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '内容盗用他人作品', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '内容盗用他人作品', mode: data.mode })"
>
<span>内容盗用他人作品</span> <span>内容盗用他人作品</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
@ -82,11 +100,17 @@
<div class="title"> <div class="title">
<span>未成年</span> <span>未成年</span>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '未成年人不当行为', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '未成年人不当行为', mode: data.mode })"
>
<span>未成年人不当行为</span> <span>未成年人不当行为</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '内容不适合未成年观看', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '内容不适合未成年观看', mode: data.mode })"
>
<span>内容不适合未成年观看</span> <span>内容不适合未成年观看</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
@ -94,41 +118,49 @@
<div class="title"> <div class="title">
<span>其他</span> <span>其他</span>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '引人不适', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '引人不适', mode: data.mode })">
<span>引人不适</span> <span>引人不适</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '疑似自我伤害', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '疑似自我伤害', mode: data.mode })"
>
<span>疑似自我伤害</span> <span>疑似自我伤害</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '诱导点赞、分享、关注', mode })"> <div
class="row"
@click="nav('/home/submit-report', { type: '诱导点赞、分享、关注', mode: data.mode })"
>
<span>诱导点赞分享关注</span> <span>诱导点赞分享关注</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
<div class="row" @click="$nav('/home/submit-report', { type: '其他', mode })"> <div class="row" @click="nav('/home/submit-report', { type: '其他', mode: data.mode })">
<span>其他</span> <span>其他</span>
<dy-back scale=".8" direction="right"></dy-back> <dy-back scale=".8" direction="right"></dy-back>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
export default { import { onMounted, reactive } from 'vue'
name: 'Report', import { useRoute } from 'vue-router'
props: {}, import { useNav } from '@/utils/hooks/useNav'
data() {
return { defineOptions({
mode: 'video' name: 'Report'
} })
},
computed: {}, const route = useRoute()
created() { const nav = useNav()
this.mode = this.$route.query.mode const data = reactive({
}, mode: 'video'
activated() {}, })
methods: {}
} onMounted(() => {
data.mode = route.query.mode as string
})
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

1003
src/pages/home/SearchPage.vue

File diff suppressed because it is too large Load Diff

78
src/pages/home/SubmitReport.vue

@ -3,9 +3,9 @@
<BaseHeader> <BaseHeader>
<template v-slot:center> <template v-slot:center>
<span class="f16"> <span class="f16">
<template v-if="mode === 'video'">视频</template> <template v-if="data.mode === 'video'">视频</template>
<template v-if="mode === 'music'">音乐</template> <template v-if="data.mode === 'music'">音乐</template>
<template v-if="mode === 'chat'">私信</template>举报</span <template v-if="data.mode === 'chat'">私信</template>举报</span
> >
</template> </template>
</BaseHeader> </BaseHeader>
@ -16,7 +16,7 @@
> >
</div> </div>
<div class="row"> <div class="row">
<span> 举报理由{{ type }} </span> <span> 举报理由{{ data.type }} </span>
</div> </div>
<div class="l-row"> <div class="l-row">
<div class="notice">举报描述(选填)</div> <div class="notice">举报描述(选填)</div>
@ -26,59 +26,61 @@
id="" id=""
cols="30" cols="30"
rows="10" rows="10"
v-model="desc" v-model="data.desc"
placeholder="详细描述举报理由" placeholder="详细描述举报理由"
></textarea> ></textarea>
</div> </div>
<div class="text-num">{{ desc.length }}/200</div> <div class="text-num">{{ data.desc.length }}/200</div>
</div> </div>
<div class="upload-photo"> <div class="upload-photo">
<div class="photo-wrapper" :key="index" v-for="(item, index) in photos"> <div class="photo-wrapper" :key="index" v-for="(item, index) in data.photos">
<img class="photo" :src="item" alt="" /> <img class="photo" :src="item" alt="" />
<img <img
class="close" class="close"
src="../../assets/img/icon/components/light-close.png" src="../../assets/img/icon/components/light-close.png"
alt="" alt=""
@click="photos.pop()" @click="data.photos.pop()"
/> />
</div> </div>
<div class="upload" @click="upload" v-if="photos.length !== 4"> <div class="upload" @click="upload" v-if="data.photos.length !== 4">
<img src="../../assets/img/icon/home/camera-gray.png" alt="" /> <img src="../../assets/img/icon/home/camera-gray.png" alt="" />
<span>{{ photos.length }}/4</span> <span>{{ data.photos.length }}/4</span>
</div> </div>
</div> </div>
<dy-button type="primary" @click="$no">提交</dy-button> <dy-button type="primary" @click="_no">提交</dy-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
export default { import { onMounted, reactive } from 'vue'
name: 'Report', import { useRoute } from 'vue-router'
props: {}, import { _hideLoading, _no, _showLoading, _sleep } from '@/utils'
data() {
return { defineOptions({
type: '色情低俗', name: 'SubmitReport'
mode: 'video', })
desc: '',
photos: [] const route = useRoute()
} const data = reactive({
}, type: '色情低俗',
computed: {}, mode: 'video',
created() { desc: '',
this.type = this.$route.query.type photos: []
this.mode = this.$route.query.mode })
},
methods: { onMounted(() => {
async upload() { data.type = route.query.type
this.$showLoading() data.mode = route.query.mode
await this.$sleep(500) })
this.$hideLoading()
this.photos.push( async function upload() {
new URL(`../../assets/img/poster/${this.photos.length}.jpg`, import.meta.url).href _showLoading()
) await _sleep(500)
} _hideLoading()
} data.photos.push(
new URL(`../../assets/img/poster/${data.photos.length}.jpg`, import.meta.url).href
)
} }
</script> </script>

15
src/pages/login/Help.vue

@ -13,17 +13,10 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
export default { defineOptions({
name: 'Help', name: 'Help'
props: {}, })
data() {
return {}
},
computed: {},
created() {},
methods: {}
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

136
src/pages/login/Login.vue

@ -2,10 +2,10 @@
<div class="login"> <div class="login">
<BaseHeader mode="light" backMode="dark" backImg="close"> <BaseHeader mode="light" backMode="dark" backImg="close">
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/login/help')">帮助与设置</span> <span class="f14" @click="nav('/login/help')">帮助与设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<Loading v-if="loading.getPhone" /> <Loading v-if="data.loading.getPhone" />
<div v-else class="content"> <div v-else class="content">
<div class="desc"> <div class="desc">
<div class="title">登录看朋友内容</div> <div class="title">登录看朋友内容</div>
@ -15,34 +15,34 @@
<dy-button <dy-button
type="primary" type="primary"
:loading="loading.login" :loading="data.loading.login"
:active="false" :active="false"
:loadingWithText="true" :loadingWithText="true"
@click="login" @click="login"
> >
{{ loading.login ? '登录中' : '一键登录' }} {{ data.loading.login ? '登录中' : '一键登录' }}
</dy-button>
<dy-button :active="false" type="white" @click="nav('/login/other')"
>其他手机号码登录
</dy-button> </dy-button>
<dy-button :active="false" type="white" @click="$nav('/login/other')"
>其他手机号码登录</dy-button
>
<div class="protocol" :class="showAnim ? 'anim-bounce' : ''"> <div class="protocol" :class="data.showAnim ? 'anim-bounce' : ''">
<Tooltip style="top: -100%; left: -10rem" v-model="showTooltip" /> <Tooltip style="top: -100%; left: -10rem" v-model="data.showTooltip" />
<div class="left"> <div class="left">
<Check v-model="isAgree" /> <Check v-model="data.isAgree" />
</div> </div>
<div class="right"> <div class="right">
我已阅读并同意 我已阅读并同意
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”用户服务协议' })" <span class="link" @click="nav('/service-protocol', { type: '“抖音”用户服务协议' })"
>用户协议</span >用户协议</span
> >
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”隐私政策' })" <span class="link" @click="nav('/service-protocol', { type: '“抖音”隐私政策' })"
>隐私政策</span >隐私政策</span
> >
<div> <div>
以及 以及
<span class="link" @click="$nav('/service-protocol', { type: '中国移动认证服务协议' })" <span class="link" @click="nav('/service-protocol', { type: '中国移动认证服务协议' })"
>中国移动认证服务条款</span >中国移动认证服务条款</span
> >
同时登录并使用抖音火山版火山小视频和抖音 同时登录并使用抖音火山版火山小视频和抖音
@ -52,74 +52,72 @@
<div class="other-login"> <div class="other-login">
<transition name="fade"> <transition name="fade">
<div v-if="isOtherLogin" class="icons"> <div v-if="data.isOtherLogin" class="icons">
<img @click="$no" src="../../assets/img/icon/login/toutiao-round.png" alt="" /> <img @click="_no" src="../../assets/img/icon/login/toutiao-round.png" alt="" />
<img @click="$no" src="../../assets/img/icon/login/qq-round.webp" alt="" /> <img @click="_no" src="../../assets/img/icon/login/qq-round.webp" alt="" />
<img @click="$no" src="../../assets/img/icon/login/wechat-round.png" alt="" /> <img @click="_no" src="../../assets/img/icon/login/wechat-round.png" alt="" />
<img @click="$no" src="../../assets/img/icon/login/weibo-round.webp" alt="" /> <img @click="_no" src="../../assets/img/icon/login/weibo-round.webp" alt="" />
</div> </div>
</transition> </transition>
</div> </div>
<transition name="fade"> <transition name="fade">
<span <span
v-if="!isOtherLogin" v-if="!data.isOtherLogin"
class="other-login-text link" class="other-login-text link"
@click="isOtherLogin = !isOtherLogin" @click="data.isOtherLogin = !data.isOtherLogin"
>其他方式登录</span >其他方式登录</span
> >
</transition> </transition>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import Check from '../../components/Check' import Check from '../../components/Check.vue'
import Tooltip from './components/Tooltip' import Tooltip from './components/Tooltip.vue'
import Loading from '../../components/Loading' import Loading from '../../components/Loading.vue'
import { onMounted, reactive } from 'vue'
export default { import { useNav } from '@/utils/hooks/useNav'
name: 'login', import { _no, _sleep } from '@/utils'
components: {
Check, defineOptions({
Tooltip, name: 'login'
Loading })
},
data() { const nav = useNav()
return { const data = reactive({
isAgree: false, isAgree: false,
isOtherLogin: false, isOtherLogin: false,
showAnim: false, showAnim: false,
showTooltip: false, showTooltip: false,
loading: { loading: {
login: false, login: false,
getPhone: false getPhone: false
} }
} })
},
computed: {}, onMounted(() => {
created() { getPhone()
this.getPhone() })
},
methods: { async function getPhone() {
async getPhone() { data.loading.getPhone = true
this.loading.getPhone = true await _sleep(1000)
await this.$sleep(1000) data.loading.getPhone = false
this.loading.getPhone = false }
},
login() { function login() {
if (this.isAgree) { if (data.isAgree) {
this.loading.login = true data.loading.login = true
} else { } else {
if (!this.showAnim && !this.showTooltip) { if (!data.showAnim && !data.showTooltip) {
this.showAnim = true data.showAnim = true
setTimeout(() => { setTimeout(() => {
this.showAnim = false data.showAnim = false
this.showTooltip = true data.showTooltip = true
}, 500) }, 500)
setTimeout(() => { setTimeout(() => {
this.showTooltip = false data.showTooltip = false
}, 3000) }, 3000)
}
}
} }
} }
} }

140
src/pages/login/VerificationCode.vue

@ -2,7 +2,7 @@
<div class="VerificationCode"> <div class="VerificationCode">
<BaseHeader mode="light" backMode="dark" backImg="back"> <BaseHeader mode="light" backMode="dark" backImg="back">
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/login/help')">帮助与设置</span> <span class="f14" @click="nav('/login/help')">帮助与设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<div class="content"> <div class="content">
@ -14,91 +14,93 @@
<LoginInput <LoginInput
autofocus autofocus
type="code" type="code"
v-model="code" v-model="data.code"
placeholder="请输入验证码" placeholder="请输入验证码"
v-model:isSendVerificationCode="isSendVerificationCode" v-model:isSendVerificationCode="data.isSendVerificationCode"
@send="sendCode" @send="sendCode"
/> />
<div class="options" v-if="showVoiceCode"> <div class="options" v-if="data.showVoiceCode">
<span> 收不到短信<span class="link" @click="getVoiceCode">获取语音验证码</span> </span> <span> 收不到短信<span class="link" @click="getVoiceCode">获取语音验证码</span> </span>
</div> </div>
<dy-button <dy-button
type="primary" type="primary"
:loading="loading" :loading="data.loading"
:active="false" :active="false"
:disabled="code.length < 4" :disabled="data.code.length < 4"
@click="login" @click="login"
> >
{{ loading ? '登录中' : '登录' }} {{ data.loading ? '登录中' : '登录' }}
</dy-button> </dy-button>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import LoginInput from './components/LoginInput' import LoginInput from './components/LoginInput.vue'
import { onMounted, reactive } from 'vue'
import { useNav } from '@/utils/hooks/useNav'
import { _hideLoading, _showConfirmDialog, _showLoading, _showNoticeDialog, _sleep } from '@/utils'
export default { defineOptions({
name: 'VerificationCode', name: 'VerificationCode'
components: { })
LoginInput
}, const nav = useNav()
data() { const data = reactive({
return { showAnim: false,
showAnim: false, showTooltip: false,
showTooltip: false, loading: false,
loading: false, phone: '',
phone: '', password: '',
password: '', code: '',
code: '', isSendVerificationCode: true,
isSendVerificationCode: true, showVoiceCode: false
showVoiceCode: false })
}
}, onMounted(() => {
created() { setTimeout(() => {
setTimeout(() => { data.showVoiceCode = true
this.showVoiceCode = true }, 3000)
}, 3000) })
},
methods: { function getVoiceCode() {
getVoiceCode() { return _showNoticeDialog(
return this.$showNoticeDialog( '语音验证码',
'语音验证码', '我们将以电话的方式告知你验证码,请注意接听',
'我们将以电话的方式告知你验证码,请注意接听', '',
'', () => {
() => {
setTimeout(() => {
this.$showConfirmDialog(
'',
'您的手机可能由于空号/欠费/停机无法收到验证码,请恢复手机号状态,如果' +
'您因为换号无法收到验证码,可以尝试找回账号',
'',
() => {},
null,
'找回账号',
'返回',
''
)
}, 2000)
},
'知道了'
)
},
//TODO loading
async sendCode() {
this.$showLoading()
await this.$sleep(500)
this.$hideLoading()
this.isSendVerificationCode = true
},
login() {
this.loading = true
setTimeout(() => { setTimeout(() => {
this.isSendVerificationCode = true _showConfirmDialog(
this.loading = false '',
}, 1000) '您的手机可能由于空号/欠费/停机无法收到验证码,请恢复手机号状态,如果' +
} '您因为换号无法收到验证码,可以尝试找回账号',
} '',
() => {},
null,
'找回账号',
'返回',
''
)
}, 2000)
},
'知道了'
)
}
//TODO loading
async function sendCode() {
_showLoading()
await _sleep(500)
_hideLoading()
data.isSendVerificationCode = true
}
function login() {
data.loading = true
setTimeout(() => {
data.isSendVerificationCode = true
data.loading = false
}, 1000)
} }
</script> </script>

208
src/pages/me/MyMusic.vue

@ -1,21 +1,21 @@
<template> <template>
<div class="MyMusic"> <div class="MyMusic">
<div class="header"> <div class="header">
<dy-back class="back" mode="light" img="back" @click="$back" /> <dy-back class="back" mode="light" img="back" @click="router.back()" />
<IndicatorLight <IndicatorLight
name="myMusicList" name="myMusicList"
:tabTexts="['猜你爱听', '我的收藏']" :tabTexts="['猜你爱听', '我的收藏']"
v-model:active-index="slideIndex" v-model:active-index="data.slideIndex"
> >
</IndicatorLight> </IndicatorLight>
<dy-back style="opacity: 0" mode="light" img="back" /> <dy-back style="opacity: 0" mode="light" img="back" />
</div> </div>
<SlideHorizontal name="myMusicList" v-model:index="slideIndex"> <SlideHorizontal name="myMusicList" v-model:index="data.slideIndex">
<SlideItem> <SlideItem>
<GuessMusic :list="guessMusic" /> <GuessMusic :list="data.guessMusic" />
</SlideItem> </SlideItem>
<SlideItem style="overflow: auto"> <SlideItem style="overflow: auto">
<Loading style="left: 150%" v-if="loading" /> <Loading style="left: 150%" v-if="data.loading" />
<div v-else class="my-collect"> <div v-else class="my-collect">
<div class="wrapper"> <div class="wrapper">
<div class="play-all"> <div class="play-all">
@ -30,25 +30,25 @@
<div <div
class="item" class="item"
:key="index" :key="index"
v-for="(item, index) in collectMusic" v-for="(item, index) in data.collectMusic"
@click="page2PlayMusic(item)" @click="page2PlayMusic(item)"
> >
<div class="left"> <div class="left">
<div class="cover-wrapper"> <div class="cover-wrapper">
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover" /> <img v-lazy="_checkImgUrl(item.cover)" alt="" class="cover" />
</div> </div>
<div class="desc"> <div class="desc">
<span class="name">{{ item.name }}</span> <span class="name">{{ item.name }}</span>
<div class="author">{{ item.author }}</div> <div class="author">{{ item.author }}</div>
<div class="desc-bottom"> <div class="desc-bottom">
<div class="tag">完整版</div> <div class="tag">完整版</div>
<div class="duration">{{ $duration(item.duration) }}</div> <div class="duration">{{ _duration(item.duration) }}</div>
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<img <img
v-if="page2SlideIndex === index" v-if="data.page2SlideIndex === index"
class="playing-icon" class="playing-icon"
src="../../assets/img/icon/me/pinlv.gif" src="../../assets/img/icon/me/pinlv.gif"
/> />
@ -59,32 +59,32 @@
<span>推荐收藏</span> <span>推荐收藏</span>
<div class="right"> <div class="right">
<span class="auto-play">自动播放</span> <span class="auto-play">自动播放</span>
<switches v-model="isAutoPlay" theme="bootstrap" color="success"></switches> <switches v-model="data.isAutoPlay" theme="bootstrap" color="success"></switches>
</div> </div>
</div> </div>
<div class="recommend-list"> <div class="recommend-list">
<div <div
class="item" class="item"
:key="index" :key="index"
v-for="(item, index) in recommendMusic" v-for="(item, index) in data.recommendMusic"
@click="page2PlayMusic(item)" @click="page2PlayMusic(item)"
> >
<div class="left"> <div class="left">
<div class="cover-wrapper"> <div class="cover-wrapper">
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover" /> <img v-lazy="_checkImgUrl(item.cover)" alt="" class="cover" />
</div> </div>
<div class="desc"> <div class="desc">
<span class="name">{{ item.name }}</span> <span class="name">{{ item.name }}</span>
<div class="author">{{ item.author }}</div> <div class="author">{{ item.author }}</div>
<div class="desc-bottom"> <div class="desc-bottom">
<div class="tag">完整版</div> <div class="tag">完整版</div>
<div class="duration">{{ $duration(item.duration) }}</div> <div class="duration">{{ _duration(item.duration) }}</div>
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<img <img
v-if="page2SlideIndex - collectMusic.length === index" v-if="data.page2SlideIndex - data.collectMusic.length === index"
class="playing-icon" class="playing-icon"
src="../../assets/img/icon/me/pinlv.gif" src="../../assets/img/icon/me/pinlv.gif"
/> />
@ -105,28 +105,32 @@
</div> </div>
</div> </div>
<transition name="float-play"> <transition name="float-play">
<div v-if="isShowFloatPlay" class="playing" @click="isShowCollectDialog = true"> <div
v-if="data.isShowFloatPlay"
class="playing"
@click="data.isShowCollectDialog = true"
>
<div class="playing-wrapper"> <div class="playing-wrapper">
<div class="cover-wrapper"> <div class="cover-wrapper">
<img v-lazy="$imgPreview(currentMusic.cover)" alt="" class="cover" /> <img v-lazy="_checkImgUrl(data.currentMusic.cover)" alt="" class="cover" />
</div> </div>
<div class="name">{{ currentMusic.name }}</div> <div class="name">{{ data.currentMusic.name }}</div>
<img <img
v-show="page2IsPlay" v-show="data.page2IsPlay"
@click.stop="togglePage2Play" @click.stop="togglePage2Play"
class="option" class="option"
src="../../assets/img/icon/me/float-pause-one.png" src="../../assets/img/icon/me/float-pause-one.png"
alt="" alt=""
/> />
<img <img
v-show="!page2IsPlay" v-show="!data.page2IsPlay"
@click.stop="togglePage2Play" @click.stop="togglePage2Play"
class="option" class="option"
src="../../assets/img/icon/me/float-play.png" src="../../assets/img/icon/me/float-play.png"
alt="" alt=""
/> />
<img <img
@click.stop="$no" @click.stop="_no"
class="menu-list" class="menu-list"
src="../../assets/img/icon/me/music-list.png" src="../../assets/img/icon/me/music-list.png"
alt="" alt=""
@ -138,104 +142,104 @@
</SlideItem> </SlideItem>
</SlideHorizontal> </SlideHorizontal>
<transition name="my-collect-dialog"> <transition name="my-collect-dialog">
<div class="my-collect-dialog" v-show="isShowCollectDialog"> <div class="my-collect-dialog" v-show="data.isShowCollectDialog">
<div class="dialog-header"> <div class="dialog-header">
<dy-back class="close" mode="light" img="back" @click="isShowCollectDialog = false" /> <dy-back
class="close"
mode="light"
img="back"
@click="data.isShowCollectDialog = false"
/>
<span>我的收藏</span> <span>我的收藏</span>
<dy-back style="opacity: 0" mode="light" img="back" /> <dy-back style="opacity: 0" mode="light" img="back" />
</div> </div>
<CollectMusic <CollectMusic
ref="CollectMusic" ref="CollectMusic"
:list="page2Music" :list="page2Music"
v-model:page2SlideIndex="page2SlideIndex" v-model:page2SlideIndex="data.page2SlideIndex"
/> />
</div> </div>
</transition> </transition>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { mapState } from 'pinia' import Switches from '../message/components/swtich/switches.vue'
import Switches from '../message/components/swtich/switches' import IndicatorLight from '../../components/slide/IndicatorLight.vue'
import IndicatorLight from '../../components/slide/IndicatorLight' import GuessMusic from './components/GuessMusic.vue'
import GuessMusic from './components/GuessMusic' import Loading from '../../components/Loading.vue'
import CollectMusic from './components/CollectMusic'
import Loading from '../../components/Loading'
import { userCollect } from '@/api/user' import { userCollect } from '@/api/user'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { computed, onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { useNav } from '@/utils/hooks/useNav'
import { _checkImgUrl, _duration, _no } from '@/utils'
defineOptions({
name: 'MyMusic'
})
const router = useRouter()
const CollectMusic = ref()
const data = reactive({
loading: false,
slideIndex: 1,
currentMusic: {
name: '告白气球',
mp3: 'https://mp32.9ku.com/upload/128/2017/02/05/858423.mp3',
cover: new URL('../../assets/img/music-cover/7.jpg', import.meta.url).href,
author: '周杰伦',
duration: 60,
use_count: 37441000,
is_collect: false,
is_play: false
},
collectMusic: [],
recommendMusic: [],
guessMusic: [],
isShowCollectDialog: false,
isShowFloatPlay: false,
isAutoPlay: true,
isCollect: false,
page2SlideIndex: -1,
page2IsPlay: false
})
//TODO page //TODO page
export default { onMounted(() => {
name: 'MyMusic', getCollectMusic()
components: { })
Switches,
IndicatorLight, const page2Music = computed(() => {
GuessMusic, return data.collectMusic.concat(data.recommendMusic)
CollectMusic, })
Loading
}, function togglePage2Play() {
data() { data.page2IsPlay = !data.page2IsPlay
return { if (data.page2IsPlay) {
loading: false, CollectMusic.value.play(data.page2SlideIndex)
slideIndex: 1, } else {
currentMusic: { CollectMusic.value.pause()
name: '告白气球', }
mp3: 'https://mp32.9ku.com/upload/128/2017/02/05/858423.mp3', }
cover: new URL('../../assets/img/music-cover/7.jpg', import.meta.url).href,
author: '周杰伦', function page2PlayMusic(item) {
duration: 60, data.currentMusic = item
use_count: 37441000, data.isShowFloatPlay = true
is_collect: false, data.page2IsPlay = true
is_play: false data.page2SlideIndex = page2Music.value.findIndex((v) => v.name === item.name)
}, data.isShowCollectDialog = true
collectMusic: [], CollectMusic.value.play(data.page2SlideIndex)
recommendMusic: [], }
guessMusic: [],
async function getCollectMusic() {
isShowCollectDialog: false, data.loading = true
isShowFloatPlay: false, let res: any = await userCollect()
data.loading = false
isAutoPlay: true, if (res.success) {
isCollect: false, data.collectMusic = res.data.music.list.slice(0, 2)
data.guessMusic = data.recommendMusic = res.data.music.list.slice(2, -1)
page2SlideIndex: -1,
page2IsPlay: false
}
},
computed: {
...mapState(useBaseStore, ['bodyWidth']),
page2Music() {
return this.collectMusic.concat(this.recommendMusic)
}
},
created() {
this.getCollectMusic()
},
methods: {
togglePage2Play() {
this.page2IsPlay = !this.page2IsPlay
if (this.page2IsPlay) {
this.$refs.CollectMusic.play(this.page2SlideIndex)
} else {
this.$refs.CollectMusic.pause()
}
},
page2PlayMusic(item) {
this.currentMusic = item
this.isShowFloatPlay = true
this.page2IsPlay = true
this.page2SlideIndex = this.page2Music.findIndex((v) => v.name === item.name)
this.isShowCollectDialog = true
this.$refs.CollectMusic.play(this.page2SlideIndex)
},
async getCollectMusic() {
this.loading = true
let res = await userCollect()
this.loading = false
if (res.code === this.SUCCESS) {
this.collectMusic = res.data.music.list.slice(0, 2)
this.guessMusic = this.recommendMusic = res.data.music.list.slice(2, -1)
}
}
} }
} }
</script> </script>

27
src/pages/me/MyRequestUpdate.vue

@ -8,34 +8,27 @@
<div class="content"> <div class="content">
<div class="request"> <div class="request">
<div class="list"> <div class="list">
<div class="item" :key="i" v-for="(item, i) in friends.all"> <div class="item" :key="i" v-for="(item, i) in store.friends.all">
<div class="left"> <div class="left">
<img :src="$imgPreview(item.avatar)" /> <img :src="_checkImgUrl(item.avatar)" />
<span class="name">{{ item.name }}</span> <span class="name">{{ item.name }}</span>
</div> </div>
<span class="time">{{ $dateFormat(item.lastLoginTime, 'D') }}</span> <span class="time">{{ _dateFormat(item.lastLoginTime, 'D') }}</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { mapState } from 'pinia'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { _checkImgUrl, _dateFormat } from '../../utils'
export default { const store = useBaseStore()
name: 'MyRequestUpdate',
components: {}, defineOptions({
data() { name: 'MyRequestUpdate'
return {} })
},
computed: {
...mapState(useBaseStore, ['friends'])
},
created() {},
methods: {}
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

94
src/pages/me/RequestUpdate.vue

@ -9,12 +9,12 @@
<img <img
src="../../assets/img/icon/menu-gray.png" src="../../assets/img/icon/menu-gray.png"
style="width: 20rem" style="width: 20rem"
@click="isShowOption = true" @click="data.isShowOption = true"
/> />
</div> </div>
</template> </template>
</BaseHeader> </BaseHeader>
<Loading v-if="loading" /> <Loading v-if="data.loading" />
<div v-else class="content"> <div v-else class="content">
<div class="none" v-if="false"> <div class="none" v-if="false">
<img src="../../assets/img/icon/none-bg1.webp" alt="" /> <img src="../../assets/img/icon/none-bg1.webp" alt="" />
@ -26,22 +26,22 @@
<!-- <div class="subtitle f12">上次发布作品2020-08-01 上次开播昨天23:12</div>--> <!-- <div class="subtitle f12">上次发布作品2020-08-01 上次开播昨天23:12</div>-->
<div class="subtitle f12">历史求更新粉丝送礼后7天未开播则退还礼物</div> <div class="subtitle f12">历史求更新粉丝送礼后7天未开播则退还礼物</div>
<div class="list"> <div class="list">
<div class="item" :key="i" v-for="(item, i) in friends.all"> <div class="item" :key="i" v-for="(item, i) in store.friends.all">
<div class="left"> <div class="left">
<img :src="$imgPreview(item.avatar)" /> <img :src="_checkImgUrl(item.avatar)" />
<span class="name">{{ item.name }}</span> <span class="name">{{ item.name }}</span>
</div> </div>
<span class="time">{{ $dateFormat(item.lastLoginTime, 'D') }}</span> <span class="time">{{ _dateFormat(item.lastLoginTime, 'D') }}</span>
</div> </div>
</div> </div>
<no-more>最多展示100位粉丝的历史求更新记录</no-more> <no-more>最多展示100位粉丝的历史求更新记录</no-more>
</div> </div>
</div> </div>
<div class="buttons"> <div class="buttons">
<dy-button type="white" :border="false" :active="false" @click="$nav('/publish')" <dy-button type="white" :border="false" :active="false" @click="nav('/publish')"
>发布作品</dy-button >发布作品
> </dy-button>
<dy-button type="primary" :active="false" @click="$no">去直播</dy-button> <dy-button type="primary" :active="false" @click="_no">去直播</dy-button>
</div> </div>
<from-bottom-dialog <from-bottom-dialog
@ -49,53 +49,53 @@
height="160rem" height="160rem"
:show-heng-gang="false" :show-heng-gang="false"
mode="white" mode="white"
v-model="isShowOption" v-model="data.isShowOption"
> >
<div class="l-row" @click="toggleRequestUpdate"> <div class="l-row" @click="toggleRequestUpdate">
{{ openRequestUpdate ? '关闭' : '开启' }}求更新提醒 {{ data.openRequestUpdate ? '关闭' : '开启' }}求更新提醒
</div> </div>
<div class="l-row" @click="$nav('/me/my-request-update')">我的求更新提醒</div> <div class="l-row" @click="nav('/me/my-request-update')">我的求更新提醒</div>
<div class="space"></div> <div class="space"></div>
<div class="l-row" @click="isShowOption = false">取消</div> <div class="l-row" @click="data.isShowOption = false">取消</div>
</from-bottom-dialog> </from-bottom-dialog>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { mapState } from 'pinia' import FromBottomDialog from '../../components/dialog/FromBottomDialog.vue'
import FromBottomDialog from '../../components/dialog/FromBottomDialog'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { onMounted, reactive } from 'vue'
import { useNav } from '@/utils/hooks/useNav'
import { _checkImgUrl, _dateFormat, _notice, _sleep } from '@/utils'
defineOptions({
name: 'RequestUpdate'
})
const nav = useNav()
const store = useBaseStore()
const data = reactive({
isShowOption: false,
loading: false,
openRequestUpdate: true
})
onMounted(() => {
getData()
})
async function getData() {
data.loading = true
await _sleep(700)
data.loading = false
}
export default { function toggleRequestUpdate() {
name: 'RequestUpdate', data.openRequestUpdate = !data.openRequestUpdate
components: { FromBottomDialog }, data.isShowOption = false
data() { if (data.openRequestUpdate) {
return { _notice('提醒已开启,再次点击可关闭')
isShowOption: false, } else {
loading: false, _notice('提醒已关闭,再次点击可开启')
openRequestUpdate: true
}
},
computed: {
...mapState(useBaseStore, ['friends'])
},
created() {
this.getData()
},
methods: {
async getData() {
this.loading = true
await this.$sleep(700)
this.loading = false
},
toggleRequestUpdate() {
this.openRequestUpdate = !this.openRequestUpdate
this.isShowOption = false
if (this.openRequestUpdate) {
this.$notice('提醒已开启,再次点击可关闭')
} else {
this.$notice('提醒已关闭,再次点击可开启')
}
}
} }
} }
</script> </script>

49
src/pages/message/RedPacketDetail.vue

@ -2,48 +2,43 @@
<div id="RedPacketDetail"> <div id="RedPacketDetail">
<BaseHeader mode="light"> <BaseHeader mode="light">
<template v-slot:right> <template v-slot:right>
<span @click="$no" class="f14" style="color: rgb(193, 135, 79)">红包记录</span> <span @click="_no" class="f14" style="color: rgb(193, 135, 79)">红包记录</span>
</template> </template>
</BaseHeader> </BaseHeader>
<div class="content"> <div class="content">
<div class="wrapper"> <div class="wrapper">
<img :src="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" class="avatar" /> <img :src="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])" alt="" class="avatar" />
<span class="belong">{{ userinfo.nickname }}的红包</span> <span class="belong">{{ store.userinfo.nickname }}的红包</span>
<div class="password">大吉大利</div> <div class="password">大吉大利</div>
<span class="money">0.01</span> <span class="money">0.01</span>
<!-- <span class="notice" @click="$nav('/me/money')">已存入我的零钱可直接使用></span>--> <!-- <span class="notice" @click="$nav('/me/money')">已存入我的零钱可直接使用></span>-->
<span class="notice" @click="$no">已存入我的零钱可直接使用></span> <span class="notice" @click="_no">已存入我的零钱可直接使用></span>
</div> </div>
<img src="../../assets/img/icon/message/chat/money-detail-bg.png" alt="" class="bg" /> <img src="../../assets/img/icon/message/chat/money-detail-bg.png" alt="" class="bg" />
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { mapState } from 'pinia'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { _checkImgUrl } from '@/utils' import { _checkImgUrl, _no } from '@/utils'
import { useRouter } from 'vue-router'
import { useNav } from '@/utils/hooks/useNav'
export default { defineOptions({
name: 'RedPacketDetail', name: 'RedPacketDetail'
components: {}, })
props: {
modelValue: { defineProps({
type: Boolean, modelValue: {
default() { type: Boolean,
return false default() {
} return false
} }
}, }
data() { })
return {} const router = useRouter()
}, const nav = useNav()
computed: { const store = useBaseStore()
...mapState(useBaseStore, ['userinfo'])
},
watch: {},
created() {},
methods: { _checkImgUrl }
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

71
src/pages/message/SetRemark.vue

@ -14,52 +14,55 @@
<div class="content"> <div class="content">
<div class="notice">备注名</div> <div class="notice">备注名</div>
<div class="input-ctn" style="margin-bottom: 1rem"> <div class="input-ctn" style="margin-bottom: 1rem">
<input type="text" v-model="remark" placeholder="请输入备注名" /> <input type="text" v-model="data.remark" placeholder="请输入备注名" />
<img <img
v-if="remark.length" v-if="data.remark.length"
class="close" class="close"
src="../../assets/img/icon/close.svg" src="../../assets/img/icon/close.svg"
alt="" alt=""
@click="remark = ''" @click="data.remark = ''"
/> />
</div> </div>
<div class="num">{{ remark.length }}/20</div> <div class="num">{{ data.remark.length }}/20</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
export default { import { computed, onMounted, reactive } from 'vue'
name: 'SetRemark', import { useRouter } from 'vue-router'
data() { import { _hideLoading, _showLoading, _showSimpleConfirmDialog, _sleep } from '@/utils'
return {
remark: '', defineOptions({
oldRemark: '' name: 'SetRemark'
} })
},
computed: { const router = useRouter()
isChanged() { const data = reactive({
return this.remark !== this.oldRemark remark: '',
} oldRemark: ''
}, })
created() {},
methods: { const isChanged = computed(() => {
back() { return data.remark !== data.oldRemark
if (this.isChanged) { })
this.$showSimpleConfirmDialog('是否保存修改', this.save, this.$back) onMounted(() => {})
} else {
this.$back() function back() {
} if (isChanged.value) {
}, _showSimpleConfirmDialog('是否保存修改', save, router.back)
async save() { } else {
if (!this.isChanged) return router.back()
this.$showLoading()
await this.$sleep(500)
this.$hideLoading()
this.$back()
}
} }
} }
async function save() {
if (!isChanged.value) return
_showLoading()
await _sleep(500)
_hideLoading()
router.back()
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

412
src/pages/message/Share2Friend.vue

@ -6,20 +6,20 @@
</template> </template>
<template v-slot:bottom> <template v-slot:bottom>
<div class="search"> <div class="search">
<div class="search-select-friends" v-if="selectFriends.length"> <div class="search-select-friends" v-if="data.selectFriends.length">
<div class="wrapper"> <div class="wrapper">
<img <img
:src="$imgPreview(item.avatar)" :src="_checkImgUrl(item.avatar)"
:key="i" :key="i"
v-for="(item, i) in selectFriends" v-for="(item, i) in data.selectFriends"
@click="toggleSelect(item)" @click="toggleSelect(item)"
/> />
</div> </div>
</div> </div>
<img v-else class="search-icon" src="../../assets/img/icon/search-gray.png" alt="" /> <img v-else class="search-icon" src="../../assets/img/icon/search-gray.png" alt="" />
<input type="text" placeholder="搜索" v-model="searchKey" /> <input type="text" placeholder="搜索" v-model="data.searchKey" />
<img <img
v-if="searchKey" v-if="data.searchKey"
@click="clear" @click="clear"
class="clear" class="clear"
src="../../assets/img/icon/components/gray-close-full.png" src="../../assets/img/icon/components/gray-close-full.png"
@ -31,36 +31,38 @@
class="is-search" class="is-search"
:style="{ :style="{
height: height:
selectFriends.length && searchResult.length data.selectFriends.length && data.searchResult.length
? 'calc(100% - 272rem)' ? 'calc(100% - 272rem)'
: 'calc(100% - 112rem)' : 'calc(100% - 112rem)'
}" }"
v-show="searchKey" v-show="data.searchKey"
> >
<div class="list" v-if="searchResult.length"> <div class="list" v-if="data.searchResult.length">
<div <div
class="local-row" class="local-row"
:key="i" :key="i"
v-for="(item, i) of searchResult" v-for="(item, i) of data.searchResult"
@click="handleClick(item)" @click="handleClick(item)"
> >
<Check mode="red" v-model="item.select" /> <Check mode="red" v-model="item.select" />
<img :src="$imgPreview(item.avatar)" alt="" /> <img :src="_checkImgUrl(item.avatar)" alt="" />
<div class="desc"> <div class="desc">
<span class="name"> <span class="name">
<span v-if="item.name.indexOf(searchKey) > -1"> <span v-if="item.name.indexOf(data.searchKey) > -1">
{{ item.name.substr(0, item.name.indexOf(searchKey)) {{ item.name.substr(0, item.name.indexOf(data.searchKey))
}}<span style="color: #ffd800">{{ searchKey }}</span }}<span style="color: #ffd800">{{ data.searchKey }}</span
>{{ item.name.substr(item.name.indexOf(searchKey) + searchKey.length) }} >{{ item.name.substr(item.name.indexOf(data.searchKey) + data.searchKey.length) }}
</span> </span>
<span v-else>{{ item.name }}</span> <span v-else>{{ item.name }}</span>
</span> </span>
<span class="account" v-if="item.account"> <span class="account" v-if="item.account">
抖音号 抖音号
<span v-if="item.account.indexOf(searchKey) > -1"> <span v-if="item.account.indexOf(data.searchKey) > -1">
{{ item.account.substr(0, item.account.indexOf(searchKey)) {{ item.account.substr(0, item.account.indexOf(data.searchKey))
}}<span style="color: #ffd800">{{ searchKey }}</span }}<span style="color: #ffd800">{{ data.searchKey }}</span
>{{ item.account.substr(item.account.indexOf(searchKey) + searchKey.length) }} >{{
item.account.substr(item.account.indexOf(data.searchKey) + data.searchKey.length)
}}
</span> </span>
<span v-else>{{ item.account }}</span> <span v-else>{{ item.account }}</span>
</span> </span>
@ -75,12 +77,12 @@
</div> </div>
<div <div
ref="list" ref="list"
:style="{ paddingBottom: selectFriends.length ? '160rem' : 0 }" :style="{ paddingBottom: data.selectFriends.length ? '160rem' : 0 }"
class="content" class="content"
@scroll="scroll" @scroll="scroll"
> >
<div class="list"> <div class="list">
<div class="row" @click="$nav('/message/joined-group-chat')"> <div class="row" @click="nav('/message/joined-group-chat')">
<span>已加入的群聊</span> <span>已加入的群聊</span>
<dy-back :scale="0.7" direction="right"></dy-back> <dy-back :scale="0.7" direction="right"></dy-back>
</div> </div>
@ -88,48 +90,48 @@
<div <div
class="local-row" class="local-row"
:key="i" :key="i"
v-for="(item, i) of friends.recent" v-for="(item, i) of data.friends.recent"
@click="toggleSelect(item)" @click="toggleSelect(item)"
> >
<Check mode="red" v-model="item.select" /> <Check mode="red" v-model="item.select" />
<img :src="$imgPreview(item.avatar)" alt="" /> <img :src="_checkImgUrl(item.avatar)" alt="" />
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</div> </div>
<div class="title">互关好友</div> <div class="title">互关好友</div>
<div <div
class="local-row" class="local-row"
:key="i" :key="i"
v-for="(item, i) of friends.eachOther" v-for="(item, i) of data.friends.eachOther"
@click="toggleSelect(item)" @click="toggleSelect(item)"
> >
<Check mode="red" v-model="item.select" /> <Check mode="red" v-model="item.select" />
<img :src="$imgPreview(item.avatar)" alt="" /> <img :src="_checkImgUrl(item.avatar)" alt="" />
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</div> </div>
<div class="title">全部</div> <div class="title">全部</div>
<div :key="name" v-for="(value, name) of friendsSort"> <div :key="name" v-for="(value, name) of data.friendsSort">
<div :class="name === '#' ? 'top' : name" class="title"> <div :class="name === '#' ? 'top' : name" class="title">
<span>{{ name }}</span> <span>{{ name }}</span>
</div> </div>
<div class="local-row" :key="i" v-for="(item, i) of value" @click="toggleSelect(item)"> <div class="local-row" :key="i" v-for="(item, i) of value" @click="toggleSelect(item)">
<Check mode="red" v-model="item.select" /> <Check mode="red" v-model="item.select" />
<img :src="$imgPreview(item.avatar)" alt="" /> <img :src="_checkImgUrl(item.avatar)" alt="" />
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</div> </div>
</div> </div>
</div> </div>
<div class="share2friend" v-if="selectFriends.length && searchResult.length"> <div class="share2friend" v-if="data.selectFriends.length && data.searchResult.length">
<div class="comment"> <div class="comment">
<textarea placeholder="有什么想和好友说的..."></textarea> <textarea placeholder="有什么想和好友说的..."></textarea>
<img class="poster" src="../../assets/img/poster/1.jpg" alt="" /> <img class="poster" src="../../assets/img/poster/1.jpg" alt="" />
</div> </div>
<div class="wrapper"> <div class="wrapper">
<div class="create-chat" v-if="selectFriends.length > 1"> <div class="create-chat" v-if="data.selectFriends.length > 1">
<Check mode="red" v-model="isCreateChat" /> <Check mode="red" v-model="data.isCreateChat" />
<span>创建群聊</span> <span>创建群聊</span>
</div> </div>
<dy-button type="primary" <dy-button type="primary"
>{{ selectFriends.length > 1 ? '分别发送' : '发送' }} >{{ data.selectFriends.length > 1 ? '分别发送' : '发送' }}
</dy-button> </dy-button>
</div> </div>
</div> </div>
@ -167,198 +169,208 @@
</div> </div>
<div <div
class="hover" class="hover"
:style="{ top: currentFixedIndicatorTop }" :style="{ top: data.currentFixedIndicatorTop }"
ref="hover" ref="hover"
v-if="currentFixedIndicator" v-if="data.currentFixedIndicator"
> >
<img src="../../assets/img/icon/components/video/water.png" alt="" /> <img src="../../assets/img/icon/components/video/water.png" alt="" />
<span>{{ currentFixedIndicator }}</span> <span>{{ data.currentFixedIndicator }}</span>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import Check from '../../components/Check' import Check from '../../components/Check.vue'
import { friends } from '@/api/user' import { friends } from '@/api/user'
export default { import { useBaseStore } from '@/store/pinia'
name: 'Share2Friend', import { onMounted, reactive, ref, watch } from 'vue'
components: { Check }, import { useRouter } from 'vue-router'
props: {}, import { useNav } from '@/utils/hooks/useNav'
computed: { import { _checkImgUrl, cloneDeep } from '@/utils'
// ...mapState(['friends']),
defineOptions({
name: 'Share2Friend'
})
const router = useRouter()
const nav = useNav()
const store = useBaseStore()
const data = reactive({
isCreateChat: false,
searchKey: '',
indexOffsetTop: {},
currentFixedIndicator: '',
currentFixedIndicatorTop: '0px',
friends: {
all: {},
recent: [],
eachOther: []
}, },
data() { selectFriends: [],
return { friendsSort: {},
isCreateChat: false, searchResult: []
searchKey: '', })
indexOffsetTop: {},
currentFixedIndicator: '', onMounted(() => {
currentFixedIndicatorTop: 0, getFriends()
friends: { let indexs = document.querySelectorAll('.index')
all: {}, indexs.forEach((v) => {
recent: [], data.indexOffsetTop[v.children[0].innerText] = v.offsetTop
eachOther: [] })
}, let items = document.querySelectorAll('.item')
selectFriends: [], let item = document.querySelector(`.item:nth-child(2)`)
friendsSort: {}, let itemHeight = item.clientHeight
searchResult: [] let ul = document.querySelector('.indicator')
} let ulOffsetTop = ul.offsetTop
}, let resetColor = 'rgb(143, 143, 158)'
watch: { ul.addEventListener('touchstart', (e) => {
searchKey(newVal) { let pageY = e.touches[0].pageY - ulOffsetTop
let temp = this.$clone(this.friends.all) let currentIndex = pageY / itemHeight
temp.map((v) => { currentIndex = Math.floor(currentIndex)
if (this.selectFriends.find((w) => w.id === v.id)) v.select = true render(currentIndex)
}) data.currentFixedIndicatorTop = e.touches[0].pageY - 28 + 'px'
this.searchResult = temp.filter((v) => { })
return v.name.includes(newVal) || v.account.includes(newVal) ul.addEventListener('touchmove', (e) => {
}) let pageY = e.touches[0].pageY - ulOffsetTop
} data.currentFixedIndicatorTop = e.touches[0].pageY - 28 + 'px'
},
created() { let currentIndex = pageY / itemHeight
this.getFriends() currentIndex = Math.floor(currentIndex)
}, if (currentIndex >= 0 && currentIndex < 27) {
mounted() {
let indexs = document.querySelectorAll('.index')
indexs.forEach((v) => {
this.indexOffsetTop[v.children[0].innerText] = v.offsetTop
})
let items = document.querySelectorAll('.item')
let item = document.querySelector(`.item:nth-child(2)`)
let itemHeight = item.clientHeight
let ul = document.querySelector('.indicator')
let ulOffsetTop = ul.offsetTop
let resetColor = 'rgb(143, 143, 158)'
ul.addEventListener('touchstart', (e) => {
let pageY = e.touches[0].pageY - ulOffsetTop
let currentIndex = pageY / itemHeight
currentIndex = Math.floor(currentIndex)
render(currentIndex) render(currentIndex)
this.currentFixedIndicatorTop = e.touches[0].pageY - 28 + 'px' }
})
ul.addEventListener('touchend', () => {
return (data.currentFixedIndicator = '')
})
let render = (currentIndex) => {
items.forEach((el) => {
el.style.color = resetColor
}) })
ul.addEventListener('touchmove', (e) => { items[currentIndex].style.color = '#fff'
let pageY = e.touches[0].pageY - ulOffsetTop data.currentFixedIndicator = items[currentIndex].innerText
this.currentFixedIndicatorTop = e.touches[0].pageY - 28 + 'px' goto(items[currentIndex])
}
let currentIndex = pageY / itemHeight })
currentIndex = Math.floor(currentIndex)
if (currentIndex >= 0 && currentIndex < 27) { watch(
render(currentIndex) () => data.searchKey,
} (newVal) => {
let temp = cloneDeep(data.friends.all)
temp.map((v) => {
if (data.selectFriends.find((w) => w.id === v.id)) v.select = true
}) })
ul.addEventListener('touchend', () => { data.searchResult = temp.filter((v) => {
return (this.currentFixedIndicator = '') return v.name.includes(newVal) || v.account.includes(newVal)
}) })
let render = (currentIndex) => { }
items.forEach((el) => { )
el.style.color = resetColor
}) function handleClick(item) {
items[currentIndex].style.color = '#fff' toggleSelect(item)
this.currentFixedIndicator = items[currentIndex].innerText data.searchKey = ''
this.goto(items[currentIndex]) }
function clear() {
console.log('clear')
data.searchKey = ''
}
function toggleSelect(item) {
//
for (let i = 0; i < data.friends.recent.length; i++) {
let v = data.friends.recent[i]
if (v.name === item.name) {
v.select = !v.select
break
} }
}, }
methods: {
handleClick(item) {
this.toggleSelect(item)
this.searchKey = ''
},
clear() {
console.log('clear')
this.searchKey = ''
},
toggleSelect(item) {
//
for (let i = 0; i < this.friends.recent.length; i++) {
let v = this.friends.recent[i]
if (v.name === item.name) {
v.select = !v.select
break
}
}
for (let i = 0; i < this.friends.eachOther.length; i++) { for (let i = 0; i < data.friends.eachOther.length; i++) {
let v = this.friends.eachOther[i] let v = data.friends.eachOther[i]
if (v.name === item.name) { if (v.name === item.name) {
v.select = !v.select v.select = !v.select
break break
} }
} }
let find = false let find = false
let keys = Object.keys(this.friendsSort) let keys = Object.keys(data.friendsSort)
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < keys.length; i++) {
let k = keys[i] let k = keys[i]
for (let j = 0; j < this.friendsSort[k].length; j++) { for (let j = 0; j < data.friendsSort[k].length; j++) {
let value = this.friendsSort[k][j] let value = data.friendsSort[k][j]
if (value.name === item.name) { if (value.name === item.name) {
value.select = !value.select value.select = !value.select
find = true find = true
break break
}
}
if (find) break
} }
}
if (find) break
}
let resIndex = this.selectFriends.findIndex((v) => v.name === item.name) let resIndex = data.selectFriends.findIndex((v) => v.name === item.name)
if (resIndex !== -1) { if (resIndex !== -1) {
item.select = false item.select = false
this.selectFriends.splice(resIndex, 1) data.selectFriends.splice(resIndex, 1)
} else { } else {
item.select = true item.select = true
this.selectFriends.push(item) data.selectFriends.push(item)
} }
}, }
async getFriends() {
let res = await friends() async function getFriends() {
console.log('getFriends', res) //TODO
if (res.code === this.SUCCESS) { let res = await friends()
this.friends = res.data console.log('getFriends', res)
this.friends.all = this.friends.all.sort((a, b) => { if (res.success) {
if (a.pinyin < b.pinyin) return -1 data.friends = res.data
if (a.pinyin > b.pinyin) return 1 data.friends.all = data.friends.all.sort((a, b) => {
return 0 if (a.pinyin < b.pinyin) return -1
}) if (a.pinyin > b.pinyin) return 1
this.friends.all.map((v) => { return 0
if (this.friendsSort[v.pinyin]) { })
this.friendsSort[v.pinyin].push(v) data.friends.all.map((v) => {
} else { if (data.friendsSort[v.pinyin]) {
this.friendsSort[v.pinyin] = [v] data.friendsSort[v.pinyin].push(v)
}
})
}
},
goto(el) {
let list = this.$refs.list
let py
if (el.dataset['index']) {
py = 'top'
} else { } else {
py = el.innerText data.friendsSort[v.pinyin] = [v]
}
if (document.querySelector(`.${py}`)) {
list.scrollTop = document.querySelector(`.${py}`).offsetTop - 100
} }
}, })
scroll(e) { }
// let isFixed = document.querySelector(`.fixed`) }
// console.log(isFixed)
// let listScrollTop = e.target.scrollTop + (isFixed ? 110 : 110) const list = ref()
let listScrollTop = e.target.scrollTop + 110
// console.log('listScrollTop', listScrollTop) function goto(el) {
let currentKey = null let py
for (const key in this.indexOffsetTop) { if (el.dataset['index']) {
// if (currentKey) break py = 'top'
let offsetTop = this.indexOffsetTop[key] } else {
// console.log('offsetTop',offsetTop) py = el.innerText
if (offsetTop < listScrollTop) { }
currentKey = key if (document.querySelector(`.${py}`)) {
} list.value.scrollTop = document.querySelector(`.${py}`).offsetTop - 100
} }
this.currentFixedIndicator = currentKey }
// console.log('currentKey', currentKey)
function scroll(e) {
// let isFixed = document.querySelector(`.fixed`)
// console.log(isFixed)
// let listScrollTop = e.target.scrollTop + (isFixed ? 110 : 110)
let listScrollTop = e.target.scrollTop + 110
// console.log('listScrollTop', listScrollTop)
let currentKey = null
for (const key in data.indexOffsetTop) {
// if (currentKey) break
let offsetTop = data.indexOffsetTop[key]
// console.log('offsetTop',offsetTop)
if (offsetTop < listScrollTop) {
currentKey = key
} }
} }
data.currentFixedIndicator = currentKey
// console.log('currentKey', currentKey)
} }
</script> </script>

691
src/pages/message/chat/Chat.vue

@ -1,9 +1,9 @@
<template> <template>
<div class="Chat"> <div class="Chat">
<div class="chat-content" @touchstart="tooltipTop = -1"> <div class="chat-content" @touchstart="data.tooltipTop = -1">
<div class="header"> <div class="header">
<div class="left"> <div class="left">
<dy-back @click="$back"></dy-back> <dy-back @click="router.back"></dy-back>
<div class="badge">12</div> <div class="badge">12</div>
<span>zzzz</span> <span>zzzz</span>
</div> </div>
@ -13,11 +13,11 @@
src="../../../assets/img/icon/message/chat/call.png" src="../../../assets/img/icon/message/chat/call.png"
alt="" alt=""
/> />
<img @click="$no" src="../../../assets/img/icon/message/chat/video-white.png" alt="" /> <img @click="_no" src="../../../assets/img/icon/message/chat/video-white.png" alt="" />
<img <img
src="../../../assets/img/icon/menu-white.png" src="../../../assets/img/icon/menu-white.png"
alt="" alt=""
@click="$nav('/message/chat/detail')" @click="nav('/message/chat/detail')"
/> />
</div> </div>
</div> </div>
@ -27,22 +27,22 @@
v-longpress="showTooltip" v-longpress="showTooltip"
:message="item" :message="item"
:key="index" :key="index"
v-for="(item, index) in messages" v-for="(item, index) in data.messages"
></ChatMessage> ></ChatMessage>
</div> </div>
<div class="footer"> <div class="footer">
<div class="toolbar" v-if="!recording"> <div class="toolbar" v-if="!data.recording">
<img src="../../../assets/img/icon/message/camera.png" alt="" class="camera" /> <img src="../../../assets/img/icon/message/camera.png" alt="" class="camera" />
<input <input
@click="typing = true" @click="data.typing = true"
@blur="typing = false" @blur="data.typing = false"
type="text" type="text"
placeholder="发送信息..." placeholder="发送信息..."
/> />
<img @click="handleClick" src="../../../assets/img/icon/message/voice-white.png" alt="" /> <img @click="handleClick" src="../../../assets/img/icon/message/voice-white.png" alt="" />
<img src="../../../assets/img/icon/message/emoji-white.png" alt="" /> <img src="../../../assets/img/icon/message/emoji-white.png" alt="" />
<img <img
@click="showOption = !showOption" @click="data.showOption = !data.showOption"
src="../../../assets/img/icon/message/add-white.png" src="../../../assets/img/icon/message/add-white.png"
alt="" alt=""
/> />
@ -50,12 +50,12 @@
<div class="record" v-else> <div class="record" v-else>
<span>按住 说话</span> <span>按住 说话</span>
<img <img
@click="recording = false" @click="data.recording = false"
src="../../../assets/img/icon/message/keyboard.png" src="../../../assets/img/icon/message/keyboard.png"
alt="" alt=""
/> />
</div> </div>
<div class="options" v-if="showOption"> <div class="options" v-if="data.showOption">
<div class="option-wrapper"> <div class="option-wrapper">
<div class="option"> <div class="option">
<img src="../../../assets/img/icon/message/photo.png" alt="" /> <img src="../../../assets/img/icon/message/photo.png" alt="" />
@ -93,7 +93,7 @@
<!-- 长按工具栏 --> <!-- 长按工具栏 -->
<transition name="tooltip"> <transition name="tooltip">
<!-- TODO 定位也有问题--> <!-- TODO 定位也有问题-->
<div class="tooltip" :style="{ top: tooltipTop + 'px' }" v-if="tooltipTop !== -1"> <div class="tooltip" :style="{ top: data.tooltipTop + 'px' }" v-if="data.tooltipTop !== -1">
<div class="options"> <div class="options">
<img src="../../../assets/img/icon/message/chat/like.png" alt="" /> <img src="../../../assets/img/icon/message/chat/like.png" alt="" />
<span>点赞</span> <span>点赞</span>
@ -128,24 +128,24 @@
<dy-back mode="light" /> <dy-back mode="light" />
<img src="../../../assets/img/icon/search-light.png" alt="" /> <img src="../../../assets/img/icon/search-light.png" alt="" />
</div> </div>
<img :src="previewImg" alt="" class="img-src" /> <img :src="data.previewImg" alt="" class="img-src" />
<div class="footer"></div> <div class="footer"></div>
</div> </div>
<!-- 红包 --> <!-- 红包 -->
<transition name="scale"> <transition name="scale">
<div class="red-packet" v-if="isShowOpenRedPacket"> <div class="red-packet" v-if="data.isShowOpenRedPacket">
<BaseMask @click="isShowOpenRedPacket = false" /> <BaseMask @click="data.isShowOpenRedPacket = false" />
<div class="content"> <div class="content">
<template v-if="isOpened"> <template v-if="data.isOpened">
<img src="../../../assets/img/icon/message/chat/bg-open.png" alt="" class="bg" /> <img src="../../../assets/img/icon/message/chat/bg-open.png" alt="" class="bg" />
<div class="wrapper"> <div class="wrapper">
<div class="top"> <div class="top">
<div class="money">0.01</div> <div class="money">0.01</div>
<div class="belong">{{ userinfo.nickname }}的红包</div> <div class="belong">{{ store.userinfo.nickname }}的红包</div>
<div class="password">大吉大利</div> <div class="password">大吉大利</div>
</div> </div>
<div class="notice" @click="$nav('/message/chat/red-packet-detail')"> <div class="notice" @click="nav('/message/chat/red-packet-detail')">
查看红包详情> 查看红包详情>
</div> </div>
</div> </div>
@ -154,13 +154,17 @@
<img src="../../../assets/img/icon/message/chat/bg-close.png" alt="" class="bg" /> <img src="../../../assets/img/icon/message/chat/bg-close.png" alt="" class="bg" />
<div class="wrapper"> <div class="wrapper">
<div class="top"> <div class="top">
<img :src="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" class="avatar" /> <img
<div class="belong">{{ userinfo.nickname }}的红包</div> :src="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])"
alt=""
class="avatar"
/>
<div class="belong">{{ store.userinfo.nickname }}的红包</div>
<div class="password">大吉大利</div> <div class="password">大吉大利</div>
</div> </div>
<div class="l-button" :class="{ opening }" @click="openRedPacket"> <div class="l-button" :class="{ opening: data.opening }" @click="openRedPacket">
<template v-if="opening"> <template v-if="data.opening">
<img src="../../../assets/img/icon/loading-white.png" alt="" /> <img src="../../../assets/img/icon/loading-white.png" alt="" />
正在打开 正在打开
</template> </template>
@ -172,23 +176,24 @@
src="../../../assets/img/icon/message/chat/close.png" src="../../../assets/img/icon/message/chat/close.png"
alt="" alt=""
class="close" class="close"
@click="isShowOpenRedPacket = false" @click="data.isShowOpenRedPacket = false"
/> />
</div> </div>
</div> </div>
</transition> </transition>
<Loading v-if="loading" /> <Loading v-if="data.loading" />
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import ChatMessage from '../components/ChatMessage' import ChatMessage from '../components/ChatMessage.vue'
import { inject, nextTick } from 'vue' import { computed, inject, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
import { mapState } from 'pinia' import Loading from '@/components/Loading.vue'
import Loading from '../../../components/Loading'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { _checkImgUrl } from '@/utils' import { _checkImgUrl, _no, _sleep } from '@/utils'
import $ from 'jquery' import $ from 'jquery'
import { useRouter } from 'vue-router'
import { useNav } from '@/utils/hooks/useNav'
let CALL_STATE = { let CALL_STATE = {
REJECT: 0, REJECT: 0,
@ -224,331 +229,333 @@ let RED_PACKET_MODE = {
SINGLE: 1, SINGLE: 1,
MULTIPLE: 2 MULTIPLE: 2
} }
export default {
name: 'Chat',
components: {
Loading,
ChatMessage
},
data() {
return {
previewImg: new URL('../../../assets/img/poster/3.jpg', import.meta.url).href,
videoCall: [],
MESSAGE_TYPE,
messages: [
{
type: MESSAGE_TYPE.TIME,
data: '',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
defineOptions({
name: 'Chat'
})
const mitt = inject('mitt')
const router = useRouter()
const nav = useNav()
const store = useBaseStore()
const data = reactive({
previewImg: new URL('../../../assets/img/poster/3.jpg', import.meta.url).href,
videoCall: [],
MESSAGE_TYPE,
messages: [
{
type: MESSAGE_TYPE.TIME,
data: '',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.MEME,
state: AUDIO_STATE.NORMAL,
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
},
loved: [
{ {
type: MESSAGE_TYPE.MEME, id: 2,
state: AUDIO_STATE.NORMAL, avatar: '../../assets/img/icon/head-image.jpg'
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
},
loved: [
{
id: 2,
avatar: '../../assets/img/icon/head-image.jpg'
},
{
id: 2,
avatar: '../../assets/img/icon/head-image.jpg'
}
]
},
{
type: MESSAGE_TYPE.IMAGE,
state: AUDIO_STATE.NORMAL,
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: 1,
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.IMAGE,
state: AUDIO_STATE.NORMAL,
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
},
readState: READ_STATE.ARRIVED
},
{
type: MESSAGE_TYPE.VIDEO_CALL,
state: CALL_STATE.REJECT,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.VIDEO_CALL,
state: CALL_STATE.RESOLVE,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.VIDEO_CALL,
state: CALL_STATE.NONE,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO_CALL,
state: CALL_STATE.REJECT,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO_CALL,
state: CALL_STATE.RESOLVE,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO_CALL,
state: CALL_STATE.NONE,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO,
state: AUDIO_STATE.NORMAL,
data: {
duration: 5,
src: ''
},
time: '2021-01-02 21:21',
user: {
id: '1',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO,
state: AUDIO_STATE.NORMAL,
data: {
duration: 10,
src: ''
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '又在刷抖音',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '我昨天@你那个视频发给我下',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '我找不到了',
time: '2021-01-02 21:21',
user: {
id: '1',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.DOUYIN_VIDEO,
state: VIDEO_STATE.VALID,
data: {
poster: new URL('../../../assets/img/poster/3.jpg', import.meta.url).href,
author: {
name: 'safasdfassafasdfassafasdfassafasdfas',
avatar: new URL('../../../assets/img/icon/head-image.jpeg', import.meta.url).href
},
title: '服了asd'
},
time: '2021-01-02 21:21',
user: {
id: '1',
avatar: '../../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.VIDEO,
state: VIDEO_STATE.VALID,
data: {
poster: new URL('../../../assets/img/poster/3.jpg', import.meta.url).href
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.MULTIPLE,
data: {
money: 5.11,
title: '大吉大利',
state: '未领取'
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
}, },
{ {
type: MESSAGE_TYPE.RED_PACKET, id: 2,
state: AUDIO_STATE.NORMAL, avatar: '../../assets/img/icon/head-image.jpg'
mode: RED_PACKET_MODE.SINGLE,
data: {
money: 5.11,
title: '大吉大利',
state: '已过期'
},
time: '2021-01-02 21:21',
user: {
id: 1,
avatar: '../../assets/img/icon/head-image.jpg'
}
} }
], ]
typing: false,
loading: false,
opening: false,
isOpened: false,
recording: false,
showOption: false,
isShowOpenRedPacket: false,
tooltipTop: -1,
tooltipTopLocation: '',
mitt: inject('mitt')
}
},
computed: {
isExpand() {
return this.showOption
}, },
isTyping() { {
return this.typing || this.isExpand type: MESSAGE_TYPE.IMAGE,
state: AUDIO_STATE.NORMAL,
data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
time: '2021-01-02 21:21',
user: {
id: 1,
avatar: '../../assets/img/icon/head-image.jpg'
}
}, },
...mapState(useBaseStore, ['userinfo']) {
}, type: MESSAGE_TYPE.IMAGE,
created() {}, state: AUDIO_STATE.NORMAL,
mounted() { data: new URL('../../../assets/img/poster/1.jpg', import.meta.url).href,
$('img').on('load', this.scrollBottom) time: '2021-01-02 21:21',
this.scrollBottom() user: {
}, id: '2739632844317827',
unmounted() { avatar: '../../assets/img/icon/head-image.jpg'
$('img').off('load', this.scrollBottom) },
}, readState: READ_STATE.ARRIVED
methods: {
handleClick() {
this.recording = true
this.showOption = false
}, },
_checkImgUrl, {
scrollBottom() { type: MESSAGE_TYPE.VIDEO_CALL,
nextTick(() => { state: CALL_STATE.REJECT,
let wrapper = this.$refs.msgWrapper data: '2021-01-02 21:44',
// console.log('wrapper.clientHeight', wrapper.clientHeight) time: '2021-01-02 21:21',
// console.log('wrapper.scrollHeight', wrapper.scrollHeight) user: {
wrapper.scrollTo({ top: wrapper.scrollHeight - wrapper.clientHeight }) id: '2739632844317827',
}) avatar: '../../assets/img/icon/head-image.jpg'
}
}, },
openRedPacket() { {
this.opening = true type: MESSAGE_TYPE.VIDEO_CALL,
setTimeout(() => { state: CALL_STATE.RESOLVE,
this.opening = false data: '2021-01-02 21:44',
this.$nav('/message/chat/red-packet-detail') time: '2021-01-02 21:21',
}, 1000) user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
}, },
async clickItem(e) { {
if (e.type === this.MESSAGE_TYPE.RED_PACKET) { type: MESSAGE_TYPE.VIDEO_CALL,
this.loading = true state: CALL_STATE.NONE,
await this.$sleep(500) data: '2021-01-02 21:44',
this.loading = false time: '2021-01-02 21:21',
this.isOpened = e.data.state === '已过期' user: {
this.isShowOpenRedPacket = true id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
} }
}, },
showTooltip(e) { {
console.log(e) type: MESSAGE_TYPE.AUDIO_CALL,
let wrapper = null state: CALL_STATE.REJECT,
e.path.map((v) => { data: '2021-01-02 21:44',
if (v && v.classList) { time: '2021-01-02 21:21',
if (v.classList.value === 'chat-wrapper') { user: {
wrapper = v id: '2739632844317827',
} avatar: '../../assets/img/icon/head-image.jpg'
}
})
if (wrapper) {
// console.log(wrapper.getBoundingClientRect())
if (wrapper.getBoundingClientRect().y - 61 > 70) {
this.tooltipTopLocation = 'top'
this.tooltipTop = wrapper.getBoundingClientRect().y - 70
} else {
this.tooltipTopLocation = 'bottom'
this.tooltipTop =
wrapper.getBoundingClientRect().y + wrapper.getBoundingClientRect().height + 10
}
} }
},
{
type: MESSAGE_TYPE.AUDIO_CALL,
state: CALL_STATE.RESOLVE,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO_CALL,
state: CALL_STATE.NONE,
data: '2021-01-02 21:44',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO,
state: AUDIO_STATE.NORMAL,
data: {
duration: 5,
src: ''
},
time: '2021-01-02 21:21',
user: {
id: '1',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.AUDIO,
state: AUDIO_STATE.NORMAL,
data: {
duration: 10,
src: ''
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '又在刷抖音',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '我昨天@你那个视频发给我下',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '我找不到了',
time: '2021-01-02 21:21',
user: {
id: '1',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.TEXT,
data: '我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了我也找不到了',
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.DOUYIN_VIDEO,
state: VIDEO_STATE.VALID,
data: {
poster: new URL('../../../assets/img/poster/3.jpg', import.meta.url).href,
author: {
name: 'safasdfassafasdfassafasdfassafasdfas',
avatar: new URL('../../../assets/img/icon/head-image.jpeg', import.meta.url).href
},
title: '服了asd'
},
time: '2021-01-02 21:21',
user: {
id: '1',
avatar: '../../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.VIDEO,
state: VIDEO_STATE.VALID,
data: {
poster: new URL('../../../assets/img/poster/3.jpg', import.meta.url).href
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.MULTIPLE,
data: {
money: 5.11,
title: '大吉大利',
state: '未领取'
},
time: '2021-01-02 21:21',
user: {
id: '2739632844317827',
avatar: '../../assets/img/icon/head-image.jpg'
}
},
{
type: MESSAGE_TYPE.RED_PACKET,
state: AUDIO_STATE.NORMAL,
mode: RED_PACKET_MODE.SINGLE,
data: {
money: 5.11,
title: '大吉大利',
state: '已过期'
},
time: '2021-01-02 21:21',
user: {
id: 1,
avatar: '../../assets/img/icon/head-image.jpg'
}
}
],
typing: false,
loading: false,
opening: false,
isOpened: false,
recording: false,
showOption: false,
isShowOpenRedPacket: false,
tooltipTop: -1,
tooltipTopLocation: ''
})
onMounted(() => {
$('img').on('load', scrollBottom)
scrollBottom()
})
onUnmounted(() => {
$('img').off('load', scrollBottom)
})
const isExpand = computed(() => {
return data.showOption
})
const isTyping = computed(() => {
return data.typing || isExpand
})
function handleClick() {
data.recording = true
data.showOption = false
}
const msgWrapper = ref()
function scrollBottom() {
nextTick(() => {
let wrapper = msgWrapper.value
// console.log('wrapper.clientHeight', wrapper.clientHeight)
// console.log('wrapper.scrollHeight', wrapper.scrollHeight)
wrapper.scrollTo({ top: wrapper.scrollHeight - wrapper.clientHeight })
})
}
function openRedPacket() {
data.opening = true
setTimeout(() => {
data.opening = false
nav('/message/chat/red-packet-detail')
}, 1000)
}
async function clickItem(e) {
if (e.type === data.MESSAGE_TYPE.RED_PACKET) {
data.loading = true
await _sleep(500)
data.loading = false
data.isOpened = e.data.state === '已过期'
data.isShowOpenRedPacket = true
}
}
function showTooltip(e) {
console.log(e)
let wrapper = null
e.path.map((v) => {
if (v && v.classList) {
if (v.classList.value === 'chat-wrapper') {
wrapper = v
}
}
})
if (wrapper) {
// console.log(wrapper.getBoundingClientRect())
if (wrapper.getBoundingClientRect().y - 61 > 70) {
data.tooltipTopLocation = 'top'
data.tooltipTop = wrapper.getBoundingClientRect().y - 70
} else {
data.tooltipTopLocation = 'bottom'
data.tooltipTop =
wrapper.getBoundingClientRect().y + wrapper.getBoundingClientRect().height + 10
} }
} }
} }

140
src/pages/message/chat/ChatDetail.vue

@ -12,10 +12,10 @@
@unfollow="unfollow(index)" @unfollow="unfollow(index)"
mode="normal-add-button" mode="normal-add-button"
:key="index" :key="index"
v-for="(item, index) in list" v-for="(item, index) in data.list"
:people="item" :people="item"
/> />
<div class="add-people" @click="$nav('/message/share-to-friend')"> <div class="add-people" @click="nav('/message/share-to-friend')">
<img src="../../../assets/img/icon/message/chat/add.png" alt="" class="head-image" /> <img src="../../../assets/img/icon/message/chat/add.png" alt="" class="head-image" />
<div class="name">多人聊天</div> <div class="name">多人聊天</div>
</div> </div>
@ -24,28 +24,28 @@
<div class="row"> <div class="row">
<div class="left">消息免打扰</div> <div class="left">消息免打扰</div>
<div class="right"> <div class="right">
<switches v-model="noMessage" theme="bootstrap" color="success"></switches> <switches v-model="data.noMessage" theme="bootstrap" color="success"></switches>
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="left">置顶聊天</div> <div class="left">置顶聊天</div>
<div class="right"> <div class="right">
<switches v-model="top" theme="bootstrap" color="success"></switches> <switches v-model="data.top" theme="bootstrap" color="success"></switches>
</div> </div>
</div> </div>
<div class="row" @click="$nav('/set-remark')"> <div class="row" @click="nav('/set-remark')">
<div class="left">设备备注</div> <div class="left">设备备注</div>
<div class="right"> <div class="right">
<dy-back direction="right" scale=".7"></dy-back> <dy-back direction="right" scale=".7"></dy-back>
</div> </div>
</div> </div>
<div class="row" @click="$nav('/home/report', { mode: 'chat' })"> <div class="row" @click="nav('/home/report', { mode: 'chat' })">
<div class="left">举报</div> <div class="left">举报</div>
<div class="right"> <div class="right">
<dy-back direction="right" scale=".7"></dy-back> <dy-back direction="right" scale=".7"></dy-back>
</div> </div>
</div> </div>
<div class="row" @click="blockDialog = true"> <div class="row" @click="data.blockDialog = true">
<div class="left">拉黑</div> <div class="left">拉黑</div>
<div class="right"> <div class="right">
<dy-back direction="right" scale=".7"></dy-back> <dy-back direction="right" scale=".7"></dy-back>
@ -53,76 +53,76 @@
</div> </div>
</div> </div>
</div> </div>
<BlockDialog v-model="blockDialog" /> <BlockDialog v-model="data.blockDialog" />
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import Switches from '../components/swtich/switches' import Switches from '../components/swtich/switches.vue'
import People from '../../people/components/People' import People from '../../people/components/People.vue'
import BlockDialog from '../components/BlockDialog' import BlockDialog from '../components/BlockDialog.vue'
import CONST_VAR from '../../../utils/const_var' import CONST_VAR from '../../../utils/const_var'
export default { import { useBaseStore } from '@/store/pinia'
name: 'ChatDetail', import { onMounted, reactive } from 'vue'
components: { import { useRouter } from 'vue-router'
Switches, import { useNav } from '@/utils/hooks/useNav'
People, import { _showConfirmDialog } from '@/utils'
BlockDialog
}, defineOptions({
data() { name: 'ChatDetail'
return { })
noMessage: false,
top: false, const router = useRouter()
blockDialog: false, const nav = useNav()
list: [ const store = useBaseStore()
{ const data = reactive({
id: '224e9a00-ffa0-4bc1-bb07-c318c7b02fa5', noMessage: false,
avatar: new URL('../../../assets/img/icon/avatar/1.png', import.meta.url).href, top: false,
name: '何以为家', blockDialog: false,
sex: '', list: [
age: null, {
idCard: null, id: '224e9a00-ffa0-4bc1-bb07-c318c7b02fa5',
phone: '', avatar: new URL('../../../assets/img/icon/avatar/1.png', import.meta.url).href,
address: null, name: '何以为家',
wechat: '', sex: '',
password: null, age: null,
lastLoginTime: '1629993515', idCard: null,
createTime: '1630035089', phone: '',
isDelete: 0, address: null,
account: '234', wechat: '',
pinyin: 'M', password: null,
select: false, lastLoginTime: '1629993515',
type: CONST_VAR.RELATE_ENUM.FOLLOW_EACH_OTHER createTime: '1630035089',
} isDelete: 0,
] account: '234',
} pinyin: 'M',
}, select: false,
computed: {}, type: CONST_VAR.RELATE_ENUM.FOLLOW_EACH_OTHER
created() {},
methods: {
t() {
this.enabled = !this.enabled
},
follow(index) {
if (this.list[index].type === this.RELATE_ENUM.FOLLOW_ME) {
this.list[index].type = this.RELATE_ENUM.FOLLOW_EACH_OTHER
}
},
unfollow(index) {
this.$showConfirmDialog(
'正在与对方相互关注,是否不再关注该用户',
null,
'gray',
() => {
this.list[index].type = this.RELATE_ENUM.FOLLOW_ME
},
() => {},
'取消关注',
'返回'
)
} }
]
})
onMounted(() => {})
function follow(index) {
if (data.list[index].type === CONST_VAR.RELATE_ENUM.FOLLOW_ME) {
data.list[index].type = CONST_VAR.RELATE_ENUM.FOLLOW_EACH_OTHER
} }
} }
function unfollow(index) {
_showConfirmDialog(
'正在与对方相互关注,是否不再关注该用户',
null,
'gray',
() => {
data.list[index].type = CONST_VAR.RELATE_ENUM.FOLLOW_ME
},
() => {},
'取消关注',
'返回'
)
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

92
src/pages/message/notice/LiveNotice.vue

@ -5,15 +5,15 @@
<span class="f16">直播通知</span> <span class="f16">直播通知</span>
</template> </template>
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/message/notice-setting', { type: 'LIVE' })">通知设置</span> <span class="f14" @click="nav('/message/notice-setting', { type: 'LIVE' })">通知设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<Loading v-if="loading" /> <Loading v-if="data.loading" />
<div class="content" v-else> <div class="content" v-else>
<Scroll ref="mainScroll"> <Scroll ref="mainScroll">
<div class="list"> <div class="list">
<NoMore /> <NoMore />
<div class="item" :key="i" v-for="(item, i) in list" @click="goDetail(item)"> <div class="item" :key="i" v-for="(item, i) in data.list" @click="goDetail(item)">
<div class="title">{{ item.title }}</div> <div class="title">{{ item.title }}</div>
<div class="time">{{ item.time }}</div> <div class="time">{{ item.time }}</div>
<div class="content-text">{{ item.content }}</div> <div class="content-text">{{ item.content }}</div>
@ -23,54 +23,50 @@
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { nextTick } from 'vue' import { nextTick, onMounted, reactive } from 'vue'
import Scroll from '../../../components/Scroll' import Scroll from '@/components/Scroll.vue'
import BasePage from '../../BasePage' import { useNav } from '@/utils/hooks/useNav'
import { _no, _sleep } from '@/utils'
export default { defineOptions({
extends: BasePage, name: 'LiveNotice'
name: 'LiveNotice', })
components: {
Scroll const nav = useNav()
}, const data = reactive({
data() { loading: false,
return { list: [
loading: false, {
list: [ title: '直播举报反馈',
{ time: '2021-10-12 12:12',
title: '直播举报反馈', content: '你已提交对用户五五开直播内容的举报,我们会在12小时内进行处理,感谢你的监督'
time: '2021-10-12 12:12',
content: '你已提交对用户五五开直播内容的举报,我们会在12小时内进行处理,感谢你的监督'
},
{
title: '举报结果通知',
time: '2021-10-12 12:12',
content:
'你举报的【五五开】的直播内容,我们将对主播进行重点观察,并进一步判定,若发现违规立刻处理,感谢你的监督'
}
]
}
},
watch: {},
computed: {},
created() {
this.getData()
},
methods: {
async getData() {
this.loading = true
await this.$sleep(700)
this.loading = false
await nextTick()
this.$refs.mainScroll.scrollBottom()
}, },
goDetail(item) { {
item.read = true title: '举报结果通知',
if (item.detail) { time: '2021-10-12 12:12',
this.$no() content:
} '你举报的【五五开】的直播内容,我们将对主播进行重点观察,并进一步判定,若发现违规立刻处理,感谢你的监督'
} }
]
})
onMounted(() => {
getData()
})
async function getData() {
data.loading = true
await _sleep(700)
data.loading = false
await nextTick()
// data.$refs.mainScroll.scrollBottom()
}
function goDetail(item) {
item.read = true
if (item.detail) {
_no()
} }
} }
</script> </script>

127
src/pages/message/notice/MoneyNotice.vue

@ -5,21 +5,19 @@
<span class="f16">钱包通知</span> <span class="f16">钱包通知</span>
</template> </template>
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/message/notice-setting', { type: 'MONEY' })" <span class="f14" @click="nav('/message/notice-setting', { type: 'MONEY' })">通知设置</span>
>通知设置</span
>
</template> </template>
</BaseHeader> </BaseHeader>
<Loading v-if="loading" /> <Loading v-if="data.loading" />
<div class="content" v-else> <div class="content" v-else>
<Scroll ref="mainScroll"> <Scroll ref="mainScroll">
<div class="list"> <div class="list">
<NoMore /> <NoMore />
<!--TODO 超过3行显示全文--> <!--TODO 超过3行显示全文-->
<div class="item" :key="i" v-for="(item, i) in list" @click="$no"> <div class="item" :key="i" v-for="(item, i) in data.list" @click="_no">
<div class="header"> <div class="header">
<div class="left"> <div class="left">
<img src="../../../assets/img/icon/msg-icon9.webp" alt="" /> <img src="@/assets/img/icon/msg-icon9.webp" alt="" />
</div> </div>
<div class="right"> <div class="right">
<template v-if="item.type === 1"> <template v-if="item.type === 1">
@ -29,8 +27,8 @@
<span>钱包任务</span> <span>钱包任务</span>
</template> </template>
<img <img
@click.stop="isShowSetting = true" @click.stop="data.isShowSetting = true"
src="../../../assets/img/icon/menu-gray.png" src="@/assets/img/icon/menu-gray.png"
alt="" alt=""
/> />
</div> </div>
@ -61,74 +59,73 @@
mode="white" mode="white"
mask-mode="dark" mask-mode="dark"
:show-heng-gang="false" :show-heng-gang="false"
v-model="isShowSetting" v-model="data.isShowSetting"
height="160rem" height="160rem"
> >
<div class="setting-dialog"> <div class="setting-dialog">
<div class="row disabled">钱包任务</div> <div class="row disabled">钱包任务</div>
<div class="row" @click="handleClick">{{ openNotice ? '关闭' : '开启' }}消息免打扰</div> <div class="row" @click="handleClick">
{{ data.openNotice ? '关闭' : '开启' }}消息免打扰
</div>
<div class="space"></div> <div class="space"></div>
<div class="row" @click="isShowSetting = false">取消</div> <div class="row" @click="data.isShowSetting = false">取消</div>
</div> </div>
</from-bottom-dialog> </from-bottom-dialog>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { nextTick } from 'vue' import { nextTick, onMounted, reactive } from 'vue'
import FromBottomDialog from '../../../components/dialog/FromBottomDialog' import FromBottomDialog from '@/components/dialog/FromBottomDialog.vue'
import Scroll from '../../../components/Scroll' import Scroll from '@/components/Scroll.vue'
import BasePage from '../../BasePage' import { useNav } from '@/utils/hooks/useNav'
import { _sleep } from '@/utils'
export default {
extends: BasePage, defineOptions({
name: 'MoneyNotice', name: 'MoneyNotice'
components: { })
FromBottomDialog,
Scroll const nav = useNav()
}, const data = reactive({
data() { loading: false,
return { isShowSetting: false,
loading: false, openNotice: false,
isShowSetting: false, list: [
openNotice: false, {
list: [ type: 1,
{ toAccountType: '退回银行卡(工商银行3333)',
type: 1, title: '红色退款发起通知',
toAccountType: '退回银行卡(工商银行3333)', time: '2021-10-12 12:12',
title: '红色退款发起通知', money: 0.01,
time: '2021-10-12 12:12', desc: '抖音红包超过24小时未被领取',
money: 0.01, toAccountTime: '2021-10-15 12:12'
desc: '抖音红包超过24小时未被领取',
toAccountTime: '2021-10-15 12:12'
},
{
type: 2,
toAccountType: '退回银行卡(工商银行3333)',
title: '卡券发放提醒',
time: '2021-10-12 12:12',
money: 0.01,
desc: '尊敬的用户,您获得1张DUO+满赠优惠券 到期时间:2021-08-26 23:23:23',
toAccountTime: '2021-10-15 12:12'
}
]
}
},
created() {
this.getData()
},
methods: {
handleClick() {
this.openNotice = !this.openNotice
this.isShowSetting = false
}, },
async getData() { {
this.loading = true type: 2,
await this.$sleep(700) toAccountType: '退回银行卡(工商银行3333)',
this.loading = false title: '卡券发放提醒',
await nextTick() time: '2021-10-12 12:12',
this.$refs.mainScroll.scrollBottom() money: 0.01,
desc: '尊敬的用户,您获得1张DUO+满赠优惠券 到期时间:2021-08-26 23:23:23',
toAccountTime: '2021-10-15 12:12'
} }
} ]
})
onMounted(() => {
getData()
})
function handleClick() {
data.openNotice = !data.openNotice
data.isShowSetting = false
}
async function getData() {
data.loading = true
await _sleep(700)
data.loading = false
await nextTick()
// data.$refs.mainScroll.scrollBottom()
} }
</script> </script>

114
src/pages/message/notice/NoticeSetting.vue

@ -8,110 +8,114 @@
<div class="content"> <div class="content">
<div class="title">消息免打扰</div> <div class="title">消息免打扰</div>
<div class="sub-title">开启后新通知将用黄点展示不再展示未读数字</div> <div class="sub-title">开启后新通知将用黄点展示不再展示未读数字</div>
<template v-if="type === 'SYSTEM'"> <template v-if="data.type === 'SYSTEM'">
<div class="row"> <div class="row">
<div class="left">系统通知</div> <div class="left">系统通知</div>
<switches v-model="option" theme="bootstrap" color="success"></switches> <switches v-model="data.option" theme="bootstrap" color="success"></switches>
</div> </div>
</template> </template>
<template v-if="type === 'TASK'"> <template v-if="data.type === 'TASK'">
<div class="row"> <div class="row">
<div class="left">运营任务</div> <div class="left">运营任务</div>
<switches v-model="option1" theme="bootstrap" color="success"></switches> <switches v-model="data.option1" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">星图(任务)</div> <div class="left">星图(任务)</div>
<switches v-model="option2" theme="bootstrap" color="success"></switches> <switches v-model="data.option2" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">成长任务</div> <div class="left">成长任务</div>
<switches v-model="option3" theme="bootstrap" color="success"></switches> <switches v-model="data.option3" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">DUO来评审团</div> <div class="left">DUO来评审团</div>
<switches v-model="option4" theme="bootstrap" color="success"></switches> <switches v-model="data.option4" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">任务中心</div> <div class="left">任务中心</div>
<switches v-model="option5" theme="bootstrap" color="success"></switches> <switches v-model="data.option5" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">中视频伙伴任务</div> <div class="left">中视频伙伴任务</div>
<switches v-model="option6" theme="bootstrap" color="success"></switches> <switches v-model="data.option6" theme="bootstrap" color="success"></switches>
</div> </div>
</template> </template>
<template v-if="type === 'LIVE'"> <template v-if="data.type === 'LIVE'">
<div class="row"> <div class="row">
<div class="left">直播</div> <div class="left">直播</div>
<switches v-model="option7" theme="bootstrap" color="success"></switches> <switches v-model="data.option7" theme="bootstrap" color="success"></switches>
</div> </div>
</template> </template>
<template v-if="type === 'MONEY'"> <template v-if="data.type === 'MONEY'">
<div class="row"> <div class="row">
<div class="left">钱包服务</div> <div class="left">钱包服务</div>
<switches v-model="option8" theme="bootstrap" color="success"></switches> <switches v-model="data.option8" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">收入服务</div> <div class="left">收入服务</div>
<switches v-model="option9" theme="bootstrap" color="success"></switches> <switches v-model="data.option9" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">零钱服务</div> <div class="left">零钱服务</div>
<switches v-model="option10" theme="bootstrap" color="success"></switches> <switches v-model="data.option10" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">抖币服务</div> <div class="left">抖币服务</div>
<switches v-model="option11" theme="bootstrap" color="success"></switches> <switches v-model="data.option11" theme="bootstrap" color="success"></switches>
</div> </div>
<div class="row"> <div class="row">
<div class="left">卡券服务</div> <div class="left">卡券服务</div>
<switches v-model="option12" theme="bootstrap" color="success"></switches> <switches v-model="data.option12" theme="bootstrap" color="success"></switches>
</div> </div>
</template> </template>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import Switches from '../components/swtich/switches' import Switches from '../components/swtich/switches.vue'
export default { import { useBaseStore } from '@/store/pinia'
name: 'NoticeSetting', import { onMounted, reactive } from 'vue'
components: { Switches }, import { useRoute, useRouter } from 'vue-router'
props: { import { useNav } from '@/utils/hooks/useNav'
modelValue: {
type: Boolean, defineOptions({
default() { name: 'NoticeSetting'
return false })
}
} defineProps({
}, modelValue: {
data() { type: Boolean,
return { default() {
option: true, return false
option1: false,
option2: false,
option3: true,
option4: false,
option5: false,
option6: false,
option7: true,
option8: true,
option9: false,
option10: false,
option11: false,
option12: false,
type: 'TASK'
} }
}, }
watch: {}, })
computed: {}, const router = useRouter()
created() { const route = useRoute()
this.type = this.$route.query.type const nav = useNav()
}, const store = useBaseStore()
mounted() {}, const data = reactive({
methods: {} option: true,
} option1: false,
option2: false,
option3: true,
option4: false,
option5: false,
option6: false,
option7: true,
option8: true,
option9: false,
option10: false,
option11: false,
option12: false,
type: 'TASK'
})
onMounted(() => {
data.type = route.query.type
})
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

156
src/pages/message/notice/TaskNotice.vue

@ -5,16 +5,16 @@
<span class="f16">任务通知</span> <span class="f16">任务通知</span>
</template> </template>
<template v-slot:right> <template v-slot:right>
<span class="f14" @click="$nav('/message/notice-setting', { type: 'TASK' })">通知设置</span> <span class="f14" @click="nav('/message/notice-setting', { type: 'TASK' })">通知设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<Loading v-if="loading" /> <Loading v-if="data.loading" />
<div class="content" v-else> <div class="content" v-else>
<Scroll ref="mainScroll"> <Scroll ref="mainScroll">
<div class="list"> <div class="list">
<NoMore /> <NoMore />
<!--TODO 超过3行显示全文--> <!--TODO 超过3行显示全文-->
<div class="item" :key="i" v-for="(item, i) in list" @click="goDetail(item)"> <div class="item" :key="i" v-for="(item, i) in data.list" @click="goDetail(item)">
<div class="header"> <div class="header">
<div class="left"> <div class="left">
<img src="../../../assets/img/icon/message/task.webp" alt="" /> <img src="../../../assets/img/icon/message/task.webp" alt="" />
@ -22,7 +22,7 @@
<div class="right"> <div class="right">
<span>成长任务</span> <span>成长任务</span>
<img <img
@click.stop="isShowSetting = true" @click.stop="data.isShowSetting = true"
src="../../../assets/img/icon/menu-gray.png" src="../../../assets/img/icon/menu-gray.png"
alt="" alt=""
/> />
@ -41,7 +41,7 @@
</div> </div>
</div> </div>
</Scroll> </Scroll>
<div class="footer" @click="$no">查看更多任务</div> <div class="footer" @click="_no">查看更多任务</div>
</div> </div>
<from-bottom-dialog <from-bottom-dialog
@ -49,95 +49,89 @@
mode="white" mode="white"
mask-mode="dark" mask-mode="dark"
:show-heng-gang="false" :show-heng-gang="false"
v-model="isShowSetting" v-model="data.isShowSetting"
height="160rem" height="160rem"
> >
<div class="setting-dialog"> <div class="setting-dialog">
<div class="row disabled">成长任务</div> <div class="row disabled">成长任务</div>
<div class="row" @click="handleClick">{{ openNotice ? '关闭' : '开启' }}消息免打扰</div> <div class="row" @click="handleClick">
{{ data.openNotice ? '关闭' : '开启' }}消息免打扰
</div>
<div class="space"></div> <div class="space"></div>
<div class="row" @click="isShowSetting = false">取消</div> <div class="row" @click="data.isShowSetting = false">取消</div>
</div> </div>
</from-bottom-dialog> </from-bottom-dialog>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import { nextTick } from 'vue' import { nextTick, onMounted, reactive } from 'vue'
import FromBottomDialog from '../../../components/dialog/FromBottomDialog' import FromBottomDialog from '@/components/dialog/FromBottomDialog.vue'
import Scroll from '../../../components/Scroll' import Scroll from '@/components/Scroll.vue'
import BasePage from '../../BasePage' import { useNav } from '@/utils/hooks/useNav'
import { _no, _sleep } from '@/utils'
export default { defineOptions({
extends: BasePage, name: 'TaskNotice'
name: 'SystemNotice', })
components: {
FromBottomDialog, const nav = useNav()
Scroll const data = reactive({
}, loading: false,
data() { isShowSetting: false,
return { openNotice: false,
loading: false, list: [
isShowSetting: false, {
openNotice: false, type: 1,
list: [ title: '发作品得流量',
{ detail: 'xxx',
type: 1, time: '2021-10-12 12:12',
title: '发作品得流量', content: '4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
detail: 'xxx',
time: '2021-10-12 12:12',
content:
'4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
},
{
type: 1,
title: '发作品得流量',
detail: 'xxx',
time: '2021-10-12 12:12',
content:
'4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
},
{
type: 1,
title: '发作品得流量',
detail: 'xxx',
time: '2021-10-12 12:12',
content:
'4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
},
{
type: 1,
title: '发作品得流量',
detail: 'xxx',
time: '2021-10-12 12:12',
content:
'4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
}
]
}
},
watch: {},
computed: {},
created() {
this.getData()
},
methods: {
handleClick() {
this.openNotice = !this.openNotice
this.isShowSetting = false
}, },
async getData() { {
this.loading = true type: 1,
await this.$sleep(700) title: '发作品得流量',
this.loading = false detail: 'xxx',
await nextTick() time: '2021-10-12 12:12',
this.$refs.mainScroll.scrollBottom() content: '4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
}, },
goDetail(item) { {
item.read = true type: 1,
if (item.detail) { title: '发作品得流量',
this.$no() detail: 'xxx',
} time: '2021-10-12 12:12',
content: '4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
},
{
type: 1,
title: '发作品得流量',
detail: 'xxx',
time: '2021-10-12 12:12',
content: '4.24-4.28,公开发布1个道具作品,即得50-100的额外流量。快来发布视频,获得更多关注'
} }
]
})
onMounted(() => {
getData()
})
function handleClick() {
data.openNotice = !data.openNotice
data.isShowSetting = false
}
async function getData() {
data.loading = true
await _sleep(700)
data.loading = false
await nextTick()
// data.$refs.mainScroll.scrollBottom()
}
function goDetail(item: any) {
item.read = true
if (item.detail) {
_no()
} }
} }
</script> </script>

2
src/pages/other/VideoDetail.vue

@ -1,7 +1,7 @@
<template> <template>
<div id="video-detail"> <div id="video-detail">
<div class="search-wrapper"> <div class="search-wrapper">
<Icon class="back" icon="icon-park-outline:left" @click="$back" /> <Icon class="back" icon="icon-park-outline:left" @click="router.back" />
<div class="search" @click="nav('/home/search')"> <div class="search" @click="nav('/home/search')">
<div class="left"> <div class="left">
<Icon class="icon" icon="ion:search" /> <Icon class="icon" icon="ion:search" />

32
src/pages/people/AddressList.vue

@ -11,32 +11,28 @@
<div class="left">已有20+位朋友加入抖音</div> <div class="left">已有20+位朋友加入抖音</div>
</div> </div>
<div class="list"> <div class="list">
<People :key="i" v-for="(item, i) in list" :people="item"></People> <People :key="i" v-for="(item, i) in data.list" :people="item"></People>
</div> </div>
</div> </div>
<div class="footer">为尊重用户选择仅展示已授权用户</div> <div class="footer">为尊重用户选择仅展示已授权用户</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import People from './components/People' import People from './components/People.vue'
import { reactive } from 'vue'
export default { defineOptions({
name: 'AddressList', name: 'AddressList'
components: { })
People
}, const data = reactive({
data() { list: [
return { {
list: [ type: 5
{
type: 5
}
]
} }
}, ]
methods: {} })
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

19
src/pages/people/FaceToFace.vue

@ -2,23 +2,20 @@
<div class="FaceToFace"> <div class="FaceToFace">
<BaseHeader style="background: black"> <BaseHeader style="background: black">
<template v-slot:right> <template v-slot:right>
<span class="f16" @click="$nav('/common-setting')">设置</span> <span class="f16" @click="nav('/common-setting')">设置</span>
</template> </template>
</BaseHeader> </BaseHeader>
<div class="content"></div> <div class="content"></div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
//TODO //TODO
export default { import { useNav } from '@/utils/hooks/useNav'
name: 'FaceToFace',
data() { defineOptions({
return {} name: 'FaceToFace'
}, })
computed: {}, const nav = useNav()
created() {},
methods: {}
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

206
src/pages/people/FindAcquaintance.vue

@ -6,41 +6,41 @@
style="width: 50%" style="width: 50%"
tabStyleWidth="40%" tabStyleWidth="40%"
:tabTexts="['发现朋友', '熟人列表']" :tabTexts="['发现朋友', '熟人列表']"
v-model:active-index="currentSlideItemIndex" v-model:active-index="data.currentSlideItemIndex"
> >
</Indicator> </Indicator>
<img <img
src="../../assets/img/icon/menu-gray.png" src="../../assets/img/icon/menu-gray.png"
alt="" alt=""
class="option" class="option"
@click="moreOptionDialog = true" @click="data.moreOptionDialog = true"
/> />
</div> </div>
<SlideHorizontal v-model:index="currentSlideItemIndex"> <SlideHorizontal v-model:index="data.currentSlideItemIndex">
<SlideItem class="tab1" style="overflow: auto"> <SlideItem class="tab1" style="overflow: auto">
<div class="mr2r ml2r mt1r"> <div class="mr2r ml2r mt1r">
<Search <Search
v-if="!isShowRightText" v-if="!data.isShowRightText"
placeholder="搜索用户名字/抖音号" placeholder="搜索用户名字/抖音号"
:is-show-right-text="false" :is-show-right-text="false"
@click="isShowRightText = true" @click="data.isShowRightText = true"
> >
<img <img
src="../../assets/img/icon/scan-gray.png" src="../../assets/img/icon/scan-gray.png"
style="width: 10rem; transform: scale(1.5)" style="width: 10rem; transform: scale(1.5)"
@click.stop="$nav('/scan')" @click.stop="nav('/scan')"
/> />
</Search> </Search>
<Search <Search
v-else v-else
v-model="searchKey" v-model="data.searchKey"
:is-show-right-text="true" :is-show-right-text="true"
@notice="search" @notice="search"
@clear="isSearch = false" @clear="data.isSearch = false"
></Search> ></Search>
</div> </div>
<div class="no-search" v-if="!isShowRightText"> <div class="no-search" v-if="!data.isShowRightText">
<div class="look-address-list" @click="findAddressListDialog = true"> <div class="look-address-list" @click="data.findAddressListDialog = true">
<img class="left" src="../../assets/img/icon/people/address-book.png" alt="" /> <img class="left" src="../../assets/img/icon/people/address-book.png" alt="" />
<div class="right"> <div class="right">
<div class="notice"> <div class="notice">
@ -60,21 +60,21 @@
</div> </div>
<People <People
:key="i" :key="i"
v-for="(item, i) in friends.all" v-for="(item, i) in store.friends.all"
:people="item" :people="item"
mode="recommend" mode="recommend"
></People> ></People>
</div> </div>
<div class="is-search" v-else> <div class="is-search" v-else>
<div class="tooltip" v-if="searchKey && !isSearch"> <div class="tooltip" v-if="data.searchKey && !data.isSearch">
<img src="../../assets/img/icon/close.svg" style="width: 10rem" /> <img src="../../assets/img/icon/close.svg" style="width: 10rem" />
搜索用户名字/抖音号<span class="searchKey">{{ searchKey }}</span> 搜索用户名字/抖音号<span class="searchKey">{{ data.searchKey }}</span>
</div> </div>
<!-- TODO --> <!-- TODO -->
<template v-if="isSearch"> <template v-if="data.isSearch">
<People <People
:key="i" :key="i"
v-for="(item, i) in friends.all" v-for="(item, i) in store.friends.all"
:people="item" :people="item"
mode="recommend" mode="recommend"
></People> ></People>
@ -83,8 +83,13 @@
</SlideItem> </SlideItem>
<SlideItem class="tab2" style="overflow: auto"> <SlideItem class="tab2" style="overflow: auto">
<Search placeholder="搜索用户备注或名字" class="mr20p ml20p mt10p"></Search> <Search placeholder="搜索用户备注或名字" class="mr20p ml20p mt10p"></Search>
<div class="title">{{ friends.all.length }} 位朋友</div> <div class="title">{{ store.friends.all.length }} 位朋友</div>
<People :key="i" v-for="(item, i) in friends.all" :people="item" mode="friend"></People> <People
:key="i"
v-for="(item, i) in store.friends.all"
:people="item"
mode="friend"
></People>
<NoMore class="mb5r" /> <NoMore class="mb5r" />
</SlideItem> </SlideItem>
</SlideHorizontal> </SlideHorizontal>
@ -95,9 +100,9 @@
<transition name="fade"> <transition name="fade">
<div <div
v-if="findAddressListDialog" v-if="data.findAddressListDialog"
class="find-address-list-dialog" class="find-address-list-dialog"
@click="findAddressListDialog = false" @click="data.findAddressListDialog = false"
> >
<div class="body"> <div class="body">
<div> <div>
@ -106,21 +111,21 @@
<span class="title">发现通讯录好友</span> <span class="title">发现通讯录好友</span>
<span class="desc"> <span class="desc">
<span>授权通讯录看看哪些好友在使用抖音具体使用场景及撤回授权方式详见</span> <span>授权通讯录看看哪些好友在使用抖音具体使用场景及撤回授权方式详见</span>
<span class="link" @click="$nav('/service-protocol', { type: '“抖音”用户服务协议' })" <span class="link" @click="nav('/service-protocol', { type: '“抖音”用户服务协议' })"
>隐私政策</span >隐私政策</span
> >
</span> </span>
</div> </div>
<div class="footer"> <div class="footer">
<div @click="findAddressListDialog = false">暂时不要</div> <div @click="data.findAddressListDialog = false">暂时不要</div>
<div @click="$nav('/address-list')">发现好友</div> <div @click="nav('/address-list')">发现好友</div>
</div> </div>
</div> </div>
</transition> </transition>
<from-bottom-dialog <from-bottom-dialog
page-id="FindAcquaintance" page-id="FindAcquaintance"
v-model="moreOptionDialog" v-model="data.moreOptionDialog"
:show-heng-gang="false" :show-heng-gang="false"
height="210rem" height="210rem"
mode="white" mode="white"
@ -129,25 +134,25 @@
<div class="row" @click="handleClick"> <div class="row" @click="handleClick">
<span>站外好友口令</span> <span>站外好友口令</span>
</div> </div>
<div class="row" @click="$nav('/scan')"> <div class="row" @click="nav('/scan')">
<span>扫一扫加好友</span> <span>扫一扫加好友</span>
</div> </div>
<div class="row" style="border-bottom: none" @click="$nav('/face-to-face')"> <div class="row" style="border-bottom: none" @click="nav('/face-to-face')">
<span>面对面加好友</span> <span>面对面加好友</span>
</div> </div>
<div class="space"></div> <div class="space"></div>
<div class="row" @click="moreOptionDialog = false">取消</div> <div class="row" @click="data.moreOptionDialog = false">取消</div>
</div> </div>
</from-bottom-dialog> </from-bottom-dialog>
<transition name="fade"> <transition name="fade">
<div class="out-web-img-account-dialog" v-if="outWebImgAccountDialog"> <div class="out-web-img-account-dialog" v-if="data.outWebImgAccountDialog">
<img src="../../assets/img/icon/head-image.jpeg" alt="" class="img-account" /> <img src="../../assets/img/icon/head-image.jpeg" alt="" class="img-account" />
<img <img
src="../../assets/img/icon/close-white.png" src="../../assets/img/icon/close-white.png"
alt="" alt=""
class="close" class="close"
@click="outWebImgAccountDialog = false" @click="data.outWebImgAccountDialog = false"
/> />
<div class="desc"> <div class="desc">
<div>这是你的图片口令</div> <div>这是你的图片口令</div>
@ -157,11 +162,11 @@
<img src="../../assets/img/icon/close.svg" alt="" /> <img src="../../assets/img/icon/close.svg" alt="" />
<span>图片口令已保存到相册</span> <span>图片口令已保存到相册</span>
</div> </div>
<div class="btn wechat" @click="outWebImgAccountDialog = false"> <div class="btn wechat" @click="data.outWebImgAccountDialog = false">
<img src="../../assets/img/icon/close.svg" alt="" /> <img src="../../assets/img/icon/close.svg" alt="" />
<span>发给微信好友</span> <span>发给微信好友</span>
</div> </div>
<div class="btn qq" @click="outWebImgAccountDialog = false"> <div class="btn qq" @click="data.outWebImgAccountDialog = false">
<img src="../../assets/img/icon/close.svg" alt="" /> <img src="../../assets/img/icon/close.svg" alt="" />
<span>发给QQ好友</span> <span>发给QQ好友</span>
</div> </div>
@ -169,83 +174,82 @@
</transition> </transition>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import People from './components/People' import People from './components/People.vue'
import Search from '../../components/Search' import Search from '../../components/Search.vue'
import Indicator from '../../components/slide/Indicator' import Indicator from '../../components/slide/Indicator.vue'
import FromBottomDialog from '../../components/dialog/FromBottomDialog' import FromBottomDialog from '../../components/dialog/FromBottomDialog.vue'
import { mapState } from 'pinia'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { computed, onMounted, reactive } from 'vue'
export default { import { useRouter } from 'vue-router'
name: 'FindAcquaintance', import { useNav } from '@/utils/hooks/useNav'
components: { import { _hideLoading, _showLoading, _sleep } from '@/utils'
People,
Search, defineOptions({
Indicator, name: 'FindAcquaintance'
FromBottomDialog })
},
data() { const router = useRouter()
return { const nav = useNav()
findAddressListDialog: false, const store = useBaseStore()
moreOptionDialog: false, const data = reactive({
outWebImgAccountDialog: false, findAddressListDialog: false,
indicatorFixed: false, moreOptionDialog: false,
isShowRightText: false, outWebImgAccountDialog: false,
isSearch: false, indicatorFixed: false,
searchKey: '', isShowRightText: false,
isSearch: false,
currentSlideItemIndex: 0, searchKey: '',
list: [
{ currentSlideItemIndex: 0,
type: 1 list: [
}, {
{ type: 1
type: 2
},
{
type: 3
},
{
type: 4
},
{
type: 5
}
]
}
},
computed: {
maskDialog: {
get() {
return this.findAddressListDialog || this.outWebImgAccountDialog
},
set() {
this.findAddressListDialog = this.outWebImgAccountDialog = false
}
}, },
...mapState(useBaseStore, ['friends']) {
}, type: 2
mounted() {},
methods: {
async search() {
this.$showLoading()
await this.$sleep(500)
this.$hideLoading()
this.isSearch = true
}, },
back() { {
if (this.isShowRightText) { type: 3
this.isShowRightText = false },
} else { {
this.$back() type: 4
}
}, },
handleClick() { {
this.outWebImgAccountDialog = true type: 5
this.moreOptionDialog = false
} }
]
})
onMounted(() => {})
const maskDialog = computed({
get() {
return data.findAddressListDialog || data.outWebImgAccountDialog
},
set() {
data.findAddressListDialog = data.outWebImgAccountDialog = false
} }
})
async function search() {
_showLoading()
await _sleep(500)
_hideLoading()
data.isSearch = true
}
function back() {
if (data.isShowRightText) {
data.isShowRightText = false
} else {
router.back()
}
}
function handleClick() {
data.outWebImgAccountDialog = true
data.moreOptionDialog = false
} }
</script> </script>

113
src/pages/people/FollowAndFans.vue

@ -2,14 +2,14 @@
<div class="FollowAndFans" id="FollowAndFans"> <div class="FollowAndFans" id="FollowAndFans">
<BaseHeader backMode="light"> <BaseHeader backMode="light">
<template v-slot:center> <template v-slot:center>
<span class="f14">{{ userinfo.nickname }}</span> <span class="f14">{{ store.userinfo.nickname }}</span>
</template> </template>
<template v-slot:right> <template v-slot:right>
<div> <div>
<img <img
src="../../assets/img/icon/people/add-user.png" src="../../assets/img/icon/people/add-user.png"
style="width: 2rem" style="width: 2rem"
@click="$nav('/people/find-acquaintance')" @click="nav('/people/find-acquaintance')"
/> />
</div> </div>
</template> </template>
@ -19,23 +19,23 @@
<Indicator <Indicator
tabStyleWidth="50%" tabStyleWidth="50%"
:tabTexts="['关注', '粉丝']" :tabTexts="['关注', '粉丝']"
v-model:active-index="slideIndex" v-model:active-index="data.slideIndex"
> >
</Indicator> </Indicator>
</div> </div>
<SlideHorizontal <SlideHorizontal
v-model:index="slideIndex" v-model:index="data.slideIndex"
style="height: calc(var(--vh, 1vh) * 100 - 111rem)" style="height: calc(var(--vh, 1vh) * 100 - 111rem)"
> >
<SlideItem class="tab1"> <SlideItem class="tab1">
<Search <Search
v-model="searchKey" v-model="data.searchKey"
placeholder="搜索用户备注或名字" placeholder="搜索用户备注或名字"
:is-show-right-text="false" :is-show-right-text="false"
/> />
<div class="is-search" v-if="searchKey"> <div class="is-search" v-if="data.searchKey">
<div class="search-result" v-if="searchFriends.length"> <div class="search-result" v-if="data.searchFriends.length">
<People :key="i" v-for="(item, i) in searchFriends" :people="item"></People> <People :key="i" v-for="(item, i) in data.searchFriends" :people="item"></People>
</div> </div>
<div class="no-result" v-else> <div class="no-result" v-else>
<img src="../../assets/img/icon/no-result.png" alt="" /> <img src="../../assets/img/icon/no-result.png" alt="" />
@ -45,75 +45,60 @@
</div> </div>
<div class="no-search" v-else> <div class="no-search" v-else>
<div class="title">我的关注</div> <div class="title">我的关注</div>
<People :key="i" v-for="(item, i) in friends.all" :people="item"></People> <People :key="i" v-for="(item, i) in store.friends.all" :people="item"></People>
</div> </div>
</SlideItem> </SlideItem>
<SlideItem class="tab2"> <SlideItem class="tab2">
<People :key="i" v-for="(item, i) in friends.all" :people="item"></People> <People :key="i" v-for="(item, i) in store.friends.all" :people="item"></People>
<NoMore /> <NoMore />
</SlideItem> </SlideItem>
</SlideHorizontal> </SlideHorizontal>
</div> </div>
</div> </div>
</template> </template>
<script> <script setup lang="ts">
import People from './components/People' import People from './components/People.vue'
import Search from '../../components/Search' import Search from '../../components/Search.vue'
import Indicator from '../../components/slide/Indicator' import Indicator from '../../components/slide/Indicator.vue'
import { mapState } from 'pinia'
import { useBaseStore } from '@/store/pinia' import { useBaseStore } from '@/store/pinia'
import { onMounted, reactive, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useNav } from '@/utils/hooks/useNav'
export default { defineOptions({
name: 'FindAcquaintance', name: 'FindAcquaintance'
components: { })
People,
Search, const router = useRouter()
Indicator const route = useRoute()
}, const nav = useNav()
data() { const store = useBaseStore()
return { const data = reactive({
isSearch: false, isSearch: false,
searchKey: '', searchKey: '',
slideIndex: 0, slideIndex: 0,
searchFriends: [] searchFriends: []
} })
},
computed: { onMounted(() => {
...mapState(useBaseStore, ['friends', 'userinfo']) data.slideIndex = ~~route.query.type
}, })
watch: {
searchKey(newVal) { watch(
if (newVal) { () => data.searchKey,
//TODO (newVal) => {
this.searchFriends = this.friends.all.filter((v) => { if (newVal) {
if (v.name.includes(newVal)) return true //TODO
return v.account.includes(newVal) data.searchFriends = store.friends.all.filter((v) => {
}) if (v.name.includes(newVal)) return true
} else { return v.account.includes(newVal)
this.searchFriends = [] })
} } else {
} data.searchFriends = []
},
created() {
this.slideIndex = ~~this.$route.query.type
},
methods: {
async search() {
this.$showLoading()
await this.$sleep(500)
this.$hideLoading()
this.isSearch = true
},
back() {
if (this.isShowRightText) {
this.isShowRightText = false
} else {
this.$back()
}
} }
} }
} )
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

15
src/pages/people/Scan.vue

@ -21,17 +21,12 @@
<div class="scan-anim"></div> <div class="scan-anim"></div>
</div> </div>
</template> </template>
<script> <script setup>
//TODO cssps p //TODO cssps p
export default {
name: 'Scan', defineOptions({
data() { name: 'Scan'
return {} })
},
computed: {},
created() {},
methods: {}
}
</script> </script>
<style scoped lang="less"> <style scoped lang="less">

1
src/router/routes.ts

@ -223,7 +223,6 @@ const routes: RouteRecordRaw[] = [
path: '/message/share-to-friend', path: '/message/share-to-friend',
component: () => import('@/pages/message/Share2Friend.vue') component: () => import('@/pages/message/Share2Friend.vue')
}, },
{ {
path: '/video-detail', path: '/video-detail',
name: 'video-detail', name: 'video-detail',

2
src/utils/index.jsx

@ -677,5 +677,5 @@ export function _notice(val) {
} }
export function _no() { export function _no() {
this.$notice('未实现') _notice('未实现')
} }

Loading…
Cancel
Save