feat: add typescript support
This commit is contained in:
parent
83d68723d9
commit
906a5728b0
@ -15,5 +15,5 @@ module.exports = {
|
||||
rules: {
|
||||
'vue/multi-word-component-names': 0
|
||||
},
|
||||
'ignorePatterns': ['vite.config.js', 'mobile-select.js']
|
||||
'ignorePatterns': ['vite.config.ts', 'mobile-select.js']
|
||||
};
|
||||
|
||||
31
.gitignore
vendored
31
.gitignore
vendored
@ -1,25 +1,30 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
/php_backend
|
||||
report.html
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
18
env.d.ts
vendored
Normal file
18
env.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare global {
|
||||
interface Navigator {
|
||||
control: any
|
||||
webkitGetUserMedia: any
|
||||
mozGetUserMedia: any
|
||||
getUserMedia: any
|
||||
}
|
||||
}
|
||||
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
export {}
|
||||
20
index.html
20
index.html
@ -14,15 +14,15 @@
|
||||
<!-- integrity="sha512-KkkY/3auRhaXDFzFMpwtZ+BrS8EBQ+GfiBxdJ9jGMi6Gg74/sYbq/IZpY593pkNjTmbeRfBwjpZo+7gcpH45Ww=="-->
|
||||
<!-- src="https://lib.baomitu.com/eruda/3.0.1/eruda.min.js"></script>-->
|
||||
<!-- <script>eruda.init();</script>-->
|
||||
<!-- <script>-->
|
||||
<!-- var _hmt = _hmt || []-->
|
||||
<!-- ;(function () {-->
|
||||
<!-- var hm = document.createElement('script')-->
|
||||
<!-- hm.src = 'https://hm.baidu.com/hm.js?6f910830f5a7d8b5f7e75d8d67458a7a'-->
|
||||
<!-- var s = document.getElementsByTagName('script')[0]-->
|
||||
<!-- s.parentNode.insertBefore(hm, s)-->
|
||||
<!-- })()-->
|
||||
<!-- </script>-->
|
||||
<!-- <script>-->
|
||||
<!-- var _hmt = _hmt || []-->
|
||||
<!-- ;(function () {-->
|
||||
<!-- var hm = document.createElement('script')-->
|
||||
<!-- hm.src = 'https://hm.baidu.com/hm.js?6f910830f5a7d8b5f7e75d8d67458a7a'-->
|
||||
<!-- var s = document.getElementsByTagName('script')[0]-->
|
||||
<!-- s.parentNode.insertBefore(hm, s)-->
|
||||
<!-- })()-->
|
||||
<!-- </script>-->
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
display: none; /* Chrome Safari */
|
||||
@ -58,6 +58,6 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
22
package.json
22
package.json
@ -1,12 +1,16 @@
|
||||
{
|
||||
"name": "my-vue-app",
|
||||
"version": "0.0.0",
|
||||
"name": "douyin-vue",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --host",
|
||||
"start": "vite --host",
|
||||
"serve": "vite --host",
|
||||
"build": "vite build --mode prod",
|
||||
"build-uni-app": "vite build --mode uni",
|
||||
"build-only": "vite build",
|
||||
"buildp-check": "run-p type-check \"build-only {@}\" --",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"report": "vite build",
|
||||
"preview": "vite preview",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
|
||||
@ -16,7 +20,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@jambonn/vue-lazyload": "1.0.9",
|
||||
"axios": "1.6.0",
|
||||
"axios": "^1.6.8",
|
||||
"axios-mock-adapter": "^1.22.0",
|
||||
"core-js": "3.21.1",
|
||||
"dayjs": "1.11.0",
|
||||
@ -34,13 +38,16 @@
|
||||
"@commitlint/cli": "^19.2.1",
|
||||
"@commitlint/config-conventional": "^19.1.0",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
"@tsconfig/node20": "^20.1.2",
|
||||
"@types/jquery": "3.5.29",
|
||||
"@types/lodash-es": "^4.17.9",
|
||||
"@types/node": "^20.11.28",
|
||||
"@vitejs/plugin-vue": "4.0.0",
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"@vue/eslint-config-prettier": "^8.0.0",
|
||||
"@vue/eslint-config-typescript": "^12.0.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"commitizen": "^4.3.0",
|
||||
"cz-conventional-changelog": "^3.3.0",
|
||||
"eslint": "^8.57.0",
|
||||
@ -50,9 +57,12 @@
|
||||
"lint-staged": "^15.2.2",
|
||||
"prettier": "^3.2.5",
|
||||
"rollup-plugin-visualizer": "^5.9.2",
|
||||
"typescript": "~5.4.0",
|
||||
"unplugin-vue-define-options": "^1.4.1",
|
||||
"vite": "4.5.3",
|
||||
"vite-plugin-cdn-import": "0.3.5"
|
||||
"vite": "^5.1.6",
|
||||
"vite-plugin-cdn-import": "0.3.5",
|
||||
"vite-plugin-commonjs": "^0.10.1",
|
||||
"vue-tsc": "^2.0.6"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,ts,vue,jsx,tsx}": [
|
||||
|
||||
849
pnpm-lock.yaml
849
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
129
src/App.vue
129
src/App.vue
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<router-view v-slot="{ Component }">
|
||||
<transition :name="transitionName">
|
||||
<keep-alive :exclude="excludeRoutes">
|
||||
<keep-alive :exclude="store.excludeRoutes">
|
||||
<component :is="Component" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
@ -17,93 +17,66 @@
|
||||
</div>
|
||||
<Call />
|
||||
</template>
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
/*
|
||||
* try {navigator.control.gesture(false);} catch (e) {} //UC浏览器关闭默认手势事件
|
||||
try {navigator.control.longpressMenu(false);} catch (e) {} //关闭长按弹出菜单
|
||||
* */
|
||||
import { mapActions, mapState } from 'pinia'
|
||||
import routes from './router/routes'
|
||||
import Call from './components/Call'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import Call from './components/Call.vue'
|
||||
import { useBaseStore } from '@/store/pinia.js'
|
||||
import { onMounted, ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
setup() {
|
||||
const isMobile = ref(/Mobi|Android|iPhone/i.test(navigator.userAgent))
|
||||
onMounted(() => {
|
||||
console.log('asdf', isMobile.value)
|
||||
})
|
||||
return { isMobile }
|
||||
},
|
||||
components: {
|
||||
Call
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
transitionName: 'go'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['excludeRoutes'])
|
||||
},
|
||||
// watch $route 决定使用哪种过渡
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.setMaskDialog({ state: false, mode: this.maskDialogMode })
|
||||
const store = useBaseStore()
|
||||
const route = useRoute()
|
||||
const isMobile = ref(/Mobi|Android|iPhone/i.test(navigator.userAgent))
|
||||
const transitionName = ref('go')
|
||||
|
||||
//footer下面的5个按钮,对跳不要用动画
|
||||
let noAnimation = [
|
||||
'/',
|
||||
'/home',
|
||||
'/slide',
|
||||
'/me',
|
||||
'/shop',
|
||||
'/message',
|
||||
'/publish',
|
||||
'/home/live',
|
||||
'slide',
|
||||
'/test'
|
||||
]
|
||||
if (noAnimation.indexOf(from.path) !== -1 && noAnimation.indexOf(to.path) !== -1) {
|
||||
return (this.transitionName = '')
|
||||
}
|
||||
|
||||
const toDepth = routes.findIndex((v) => v.path === to.path)
|
||||
const fromDepth = routes.findIndex((v) => v.path === from.path)
|
||||
this.transitionName = toDepth > fromDepth ? 'go' : 'back'
|
||||
// watch $route 决定使用哪种过渡
|
||||
watch(
|
||||
() => route.path,
|
||||
(to, from) => {
|
||||
store.setMaskDialog({ state: false, mode: store.maskDialogMode })
|
||||
//footer下面的5个按钮,对跳不要用动画
|
||||
let noAnimation = [
|
||||
'/',
|
||||
'/home',
|
||||
'/slide',
|
||||
'/me',
|
||||
'/shop',
|
||||
'/message',
|
||||
'/publish',
|
||||
'/home/live',
|
||||
'slide',
|
||||
'/test'
|
||||
]
|
||||
if (noAnimation.indexOf(from) !== -1 && noAnimation.indexOf(to) !== -1) {
|
||||
return (transitionName.value = '')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions(useBaseStore, ['init', 'setMaskDialog']),
|
||||
setVh() {
|
||||
let vh = window.innerHeight * 0.01
|
||||
document.documentElement.style.setProperty('--vh', `${vh}px`)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
this.setVh()
|
||||
// 监听resize事件 视图大小发生变化就重新计算1vh的值
|
||||
window.addEventListener('resize', () => {
|
||||
location.reload()
|
||||
this.setVh()
|
||||
})
|
||||
|
||||
try {
|
||||
navigator.control.gesture(false)
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
try {
|
||||
navigator.control.longpressMenu(false)
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
document.onselectstart = new Function('return false') //禁止选中文字
|
||||
const toDepth = routes.findIndex((v: RouteRecordRaw) => v.path === to)
|
||||
const fromDepth = routes.findIndex((v: RouteRecordRaw) => v.path === from)
|
||||
transitionName.value = toDepth > fromDepth ? 'go' : 'back'
|
||||
}
|
||||
)
|
||||
|
||||
function setVh() {
|
||||
let vh = window.innerHeight * 0.01
|
||||
document.documentElement.style.setProperty('--vh', `${vh}px`)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
store.init()
|
||||
setVh()
|
||||
// 监听resize事件 视图大小发生变化就重新计算1vh的值
|
||||
window.addEventListener('resize', () => {
|
||||
location.reload()
|
||||
setVh()
|
||||
})
|
||||
//禁止选中文字
|
||||
document.onselectstart = new Function('return false') as any
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'AutoInput',
|
||||
props: {
|
||||
|
||||
@ -1,54 +1,59 @@
|
||||
<template>
|
||||
<div id="BaseHeader" :class="[isFixed ? 'fixed' : '']">
|
||||
<div id="BaseHeader" :class="[props.isFixed ? 'fixed' : '']">
|
||||
<div class="header">
|
||||
<dy-back :mode="backMode" :img="backImg" @click="back()" class="left" direction="left" />
|
||||
<dy-back
|
||||
:mode="props.backMode"
|
||||
:img="props.backImg"
|
||||
@click="back"
|
||||
class="left"
|
||||
direction="left"
|
||||
/>
|
||||
<slot name="center"><span></span></slot>
|
||||
<slot name="right"><span></span></slot>
|
||||
</div>
|
||||
<slot name="bottom"></slot>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'BaseHeader',
|
||||
components: {},
|
||||
props: {
|
||||
backMode: {
|
||||
type: String,
|
||||
default: 'gray'
|
||||
},
|
||||
backImg: {
|
||||
type: String,
|
||||
default: 'back'
|
||||
},
|
||||
isClose: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isFixed: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { useAttrs } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'BaseHeader'
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
backMode: {
|
||||
type: String,
|
||||
default: 'gray'
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
backImg: {
|
||||
type: String,
|
||||
default: 'back'
|
||||
},
|
||||
created() {},
|
||||
computed: {},
|
||||
methods: {
|
||||
back() {
|
||||
if (this.$attrs.onBack) {
|
||||
this.$attrs.onBack()
|
||||
} else {
|
||||
this.$back()
|
||||
}
|
||||
}
|
||||
isClose: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isFixed: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
const router = useRouter()
|
||||
const attrs: any = useAttrs()
|
||||
|
||||
function back() {
|
||||
if (attrs.onBack) {
|
||||
attrs.onBack()
|
||||
} else {
|
||||
router.back()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../assets/less/index';
|
||||
@import '@/assets/less/index';
|
||||
|
||||
#BaseHeader {
|
||||
width: 100%;
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<template v-slot:header>
|
||||
<div class="title">
|
||||
<dy-back mode="dark" img="close" direction="right" style="opacity: 0" />
|
||||
<div class="num">{{ formatNumber(comments.length) }}条评论</div>
|
||||
<div class="num">{{ _formatNumber(comments.length) }}条评论</div>
|
||||
<div class="right">
|
||||
<Icon icon="prime:arrow-up-right-and-arrow-down-left-from-center" @click.stop="$no" />
|
||||
<Icon icon="ic:round-close" @click.stop="cancel" />
|
||||
@ -36,7 +36,7 @@
|
||||
<div class="time-wrapper">
|
||||
<div class="left">
|
||||
<div class="time">
|
||||
{{ $time(item.create_time)
|
||||
{{ _time(item.create_time)
|
||||
}}{{ item.ip_location && ` · ${item.ip_location}` }}
|
||||
</div>
|
||||
<div class="reply-text">回复</div>
|
||||
@ -84,7 +84,7 @@
|
||||
<div class="time-wrapper">
|
||||
<div class="left">
|
||||
<div class="time">
|
||||
{{ $time(child.create_time)
|
||||
{{ _time(child.create_time)
|
||||
}}{{ child.ip_location && ` · ${item.ip_location}` }}
|
||||
</div>
|
||||
<div class="reply-text">回复</div>
|
||||
@ -104,7 +104,7 @@
|
||||
v-show="!child.user_digged"
|
||||
class="love-image"
|
||||
/>
|
||||
<span>{{ formatNumber(child.digg_count) }}</span>
|
||||
<span>{{ _formatNumber(child.digg_count) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -139,7 +139,7 @@
|
||||
<img
|
||||
:style="item.select ? 'opacity: .5;' : ''"
|
||||
class="avatar"
|
||||
:src="$imgPreview(item.avatar)"
|
||||
:src="_checkImgUrl(item.avatar)"
|
||||
alt=""
|
||||
/>
|
||||
<span>{{ item.name }}</span>
|
||||
@ -170,14 +170,22 @@
|
||||
</from-bottom-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AutoInput from './AutoInput'
|
||||
import ConfirmDialog from './dialog/ConfirmDialog'
|
||||
<script lang="ts">
|
||||
import AutoInput from './AutoInput.vue'
|
||||
import ConfirmDialog from './dialog/ConfirmDialog.vue'
|
||||
import { mapState } from 'pinia'
|
||||
import FromBottomDialog from './dialog/FromBottomDialog'
|
||||
import Loading from './Loading'
|
||||
import Search from './Search'
|
||||
import { $no, _checkImgUrl, _formatNumber, sampleSize } from '@/utils'
|
||||
import FromBottomDialog from './dialog/FromBottomDialog.vue'
|
||||
import Loading from './Loading.vue'
|
||||
import Search from './Search.vue'
|
||||
import {
|
||||
$no,
|
||||
_checkImgUrl,
|
||||
_formatNumber,
|
||||
_showSelectDialog,
|
||||
_sleep,
|
||||
_time,
|
||||
sampleSize
|
||||
} from '@/utils'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { videoComments } from '@/api/videos'
|
||||
|
||||
@ -243,13 +251,14 @@ export default {
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
_time,
|
||||
_formatNumber,
|
||||
_checkImgUrl,
|
||||
$no,
|
||||
async handShowChildren(item) {
|
||||
this.loadChildrenItemCId = item.comment_id
|
||||
this.loadChildren = true
|
||||
await this.$sleep(500)
|
||||
await _sleep(500)
|
||||
this.loadChildren = false
|
||||
if (item.showChildren) {
|
||||
item.children = item.children.concat(sampleSize(this.comments, 10))
|
||||
@ -273,7 +282,7 @@ export default {
|
||||
this.isCall = false
|
||||
},
|
||||
async getData() {
|
||||
let res = await videoComments({ id: this.videoId })
|
||||
let res: any = await videoComments({ id: this.videoId })
|
||||
if (res.success) {
|
||||
res.data.map((v) => {
|
||||
v.showChildren = false
|
||||
@ -304,19 +313,12 @@ export default {
|
||||
row.user_digged = !row.user_digged
|
||||
},
|
||||
showOptions(row) {
|
||||
this.$showSelectDialog(this.options, (e) => {
|
||||
_showSelectDialog(this.options, (e) => {
|
||||
if (e.id === 1) {
|
||||
this.selectRow = row
|
||||
this.showPrivateChat = true
|
||||
}
|
||||
})
|
||||
},
|
||||
// showComment() {
|
||||
// this.isCommenting = !this.isCommenting;
|
||||
// console.log(666)
|
||||
// }
|
||||
call() {
|
||||
console.log(this.commit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div id="UserPanel" @scroll="scroll" ref="page">
|
||||
<div ref="float" class="float" :class="state.floatFixed ? 'fixed' : ''">
|
||||
<div class="left">
|
||||
<Icon @click="$emit('back')" class="icon" icon="eva:arrow-ios-back-fill" />
|
||||
<Icon @click="emit('back')" class="icon" icon="eva:arrow-ios-back-fill" />
|
||||
<transition name="fade">
|
||||
<div class="float-user" v-if="state.floatFixed">
|
||||
<img
|
||||
@ -33,7 +33,7 @@
|
||||
</div>
|
||||
</transition>
|
||||
<Icon class="icon" icon="ion:search" @click.stop="$no()" />
|
||||
<Icon class="icon" icon="ri:more-line" @click.stop="$emit('showFollowSetting')" />
|
||||
<Icon class="icon" icon="ri:more-line" @click.stop="emit('showFollowSetting')" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -163,7 +163,7 @@
|
||||
<span>关注</span>
|
||||
</div>
|
||||
<div class="followed">
|
||||
<div class="l-button" @click="$emit('showFollowSetting2')">
|
||||
<div class="l-button" @click="emit('showFollowSetting2')">
|
||||
<span>已关注</span>
|
||||
<Icon icon="bxs:down-arrow" class="arrow" />
|
||||
</div>
|
||||
@ -232,11 +232,11 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import Utils, { $no, _checkImgUrl, _getUserDouyinId } from '@/utils'
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
import Posters from '@/components/Posters'
|
||||
import Posters from '@/components/Posters.vue'
|
||||
import { DefaultUser } from '@/utils/const_var'
|
||||
import Loading from '@/components/Loading.vue'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
@ -244,7 +244,13 @@ import { userVideoList } from '@/api/user'
|
||||
|
||||
const $nav = useNav()
|
||||
const baseStore = useBaseStore()
|
||||
const emit = defineEmits(['update:currentItem', 'back'])
|
||||
const emit = defineEmits<{
|
||||
'update:currentItem': [val: any]
|
||||
back: []
|
||||
showFollowSetting: []
|
||||
showFollowSetting2: []
|
||||
}>()
|
||||
|
||||
const props = defineProps({
|
||||
currentItem: {
|
||||
type: Object,
|
||||
@ -272,9 +278,7 @@ const state = reactive({
|
||||
previewImg: '',
|
||||
floatFixed: false,
|
||||
showFollowSetting: false,
|
||||
|
||||
floatHeight: 52,
|
||||
|
||||
loadings: {
|
||||
showRecommend: false
|
||||
},
|
||||
@ -296,7 +300,7 @@ watch(
|
||||
if (newVal && !props.currentItem.aweme_list.length) {
|
||||
// console.log('props.currentItem',props.currentItem)
|
||||
let id = _getUserDouyinId(props.currentItem)
|
||||
let r = await userVideoList({ id })
|
||||
let r: any = await userVideoList({ id })
|
||||
if (r.success) {
|
||||
setTimeout(() => {
|
||||
r.data = r.data.map((a) => {
|
||||
@ -326,6 +330,10 @@ function stop(e) {
|
||||
|
||||
function followButton() {}
|
||||
|
||||
function cancelFollow() {}
|
||||
|
||||
defineExpose({ cancelFollow })
|
||||
|
||||
function scroll() {
|
||||
// console.log('scroll', page.value.scrollTop)
|
||||
let scrollTop = page.value.scrollTop
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script lang="ts">
|
||||
/*TODO 单独使用时,没有mark*/
|
||||
export default {
|
||||
name: 'ConfirmDialog',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
||||
import GM from '../../utils'
|
||||
import {
|
||||
@ -73,20 +73,30 @@ onUnmounted(() => {
|
||||
ob.disconnect()
|
||||
})
|
||||
|
||||
function touchStart(e) {
|
||||
function touchStart(e: TouchEvent) {
|
||||
slideTouchStart(e, wrapperEl.value, state)
|
||||
}
|
||||
|
||||
function touchMove(e) {
|
||||
slideTouchMove(e, wrapperEl.value, state, judgeValue, canNext, null, SlideType.HORIZONTAL)
|
||||
function touchMove(e: TouchEvent) {
|
||||
slideTouchMove(
|
||||
e,
|
||||
wrapperEl.value,
|
||||
state,
|
||||
judgeValue,
|
||||
canNext,
|
||||
null,
|
||||
SlideType.HORIZONTAL,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
function touchEnd(e) {
|
||||
function touchEnd(e: TouchEvent) {
|
||||
slideTouchEnd(e, state, canNext, () => {})
|
||||
slideReset(wrapperEl.value, state, SlideType.HORIZONTAL, emit)
|
||||
}
|
||||
|
||||
function canNext(isNext) {
|
||||
function canNext(isNext: boolean) {
|
||||
return !(
|
||||
(state.localIndex === 0 && !isNext) ||
|
||||
(state.localIndex === state.wrapper.childrenLength - 1 && isNext)
|
||||
@ -95,7 +105,7 @@ function canNext(isNext) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="slide hhhh">
|
||||
<div class="slide horizontal">
|
||||
<div
|
||||
class="slide-list"
|
||||
ref="wrapperEl"
|
||||
|
||||
@ -4,8 +4,8 @@ export default {
|
||||
filePreview: 'http://192.168.0.103/static/uploads/'
|
||||
}
|
||||
const BASE_URL_MAP = {
|
||||
DEV: './',
|
||||
PROD: './',
|
||||
DEV: '',
|
||||
PROD: '',
|
||||
UNI: 'https://dy.ttentau.top'
|
||||
}
|
||||
|
||||
|
||||
@ -1,21 +1,17 @@
|
||||
import * as Vue from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import mitt from 'mitt'
|
||||
import './assets/less/index.less'
|
||||
import { startMock } from './mock'
|
||||
import { startMock } from '@/mock'
|
||||
import router from './router'
|
||||
import mixin from './utils/mixin'
|
||||
import VueLazyload from '@jambonn/vue-lazyload'
|
||||
import { createPinia } from 'pinia'
|
||||
|
||||
const pinia = createPinia()
|
||||
|
||||
// const vConsole = new VConsole();
|
||||
const emitter = mitt()
|
||||
|
||||
const app = Vue.createApp(App)
|
||||
const app = createApp(App)
|
||||
app.config.globalProperties.emitter = emitter
|
||||
app.config.unwrapInjectedRef = true
|
||||
app.provide('mitt', emitter)
|
||||
app.mixin(mixin)
|
||||
const loadImage = new URL('./assets/img/icon/img-loading.png', import.meta.url).href
|
||||
@ -24,8 +20,8 @@ app.use(VueLazyload, {
|
||||
loading: loadImage,
|
||||
attempt: 1
|
||||
})
|
||||
app.use(router)
|
||||
app.use(pinia)
|
||||
app.use(router)
|
||||
app.mount('#app')
|
||||
|
||||
//放到最后才可以使用pinia
|
||||
@ -8,22 +8,22 @@ import MockAdapter from 'axios-mock-adapter'
|
||||
|
||||
const mock = new MockAdapter(axiosInstance, { delayResponse: 300 })
|
||||
|
||||
function getPage2(params) {
|
||||
let offset = params.pageNo * params.pageSize
|
||||
let limit = params.pageNo * params.pageSize + params.pageSize
|
||||
function getPage2(params: any): { limit: number; offset: number; pageNo: number } {
|
||||
const offset = params.pageNo * params.pageSize
|
||||
const limit = params.pageNo * params.pageSize + params.pageSize
|
||||
return { limit, offset, pageNo: params.pageNo }
|
||||
}
|
||||
|
||||
let allRecommendPosts = []
|
||||
let userVideos = []
|
||||
let allRecommendVideos = posts6.map((v) => {
|
||||
let allRecommendVideos = posts6.map((v: any) => {
|
||||
v.type = 'recommend-video'
|
||||
return v
|
||||
})
|
||||
|
||||
// console.log('allRecommendVideos', allRecommendVideos)
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let t = [
|
||||
// eslint-disable-next-line
|
||||
const t = [
|
||||
{
|
||||
type: 'imgs',
|
||||
src: `https://imgapi.cn/bing.php`,
|
||||
@ -74,7 +74,7 @@ async function fetchData() {
|
||||
}
|
||||
v = v.map((w) => {
|
||||
w.type = 'recommend-video'
|
||||
let item = userList.find((a) => String(a.uid) === String(w.author_user_id))
|
||||
const item: any = userList.find((a) => String(a.uid) === String(w.author_user_id))
|
||||
if (item) w.author = item
|
||||
return w
|
||||
})
|
||||
@ -86,7 +86,7 @@ async function fetchData() {
|
||||
//TODO 有个bug,一开始只返回了6条数据,但第二次前端传过来的pageNo是2了,就是会从第10条数据开始返回,导致中间漏了4条
|
||||
export async function startMock() {
|
||||
mock.onGet(/video\/recommended/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
console.log('allRecommendVideos', cloneDeep(allRecommendVideos.length), page)
|
||||
return [
|
||||
200,
|
||||
@ -102,7 +102,7 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/video\/comments/).reply(async (config) => {
|
||||
let videoIds = [
|
||||
const videoIds = [
|
||||
'7260749400622894336',
|
||||
'7128686458763889956',
|
||||
'7293100687989148943',
|
||||
@ -124,8 +124,8 @@ export async function startMock() {
|
||||
if (!videoIds.includes(String(id))) {
|
||||
id = videoIds[random(0, videoIds.length - 1)]
|
||||
}
|
||||
let r2 = await fetch(`${FILE_URL}/comments/video_id_${id}.json`)
|
||||
let v = await r2.json()
|
||||
const r2 = await fetch(`${FILE_URL}/comments/video_id_${id}.json`)
|
||||
const v = await r2.json()
|
||||
if (v) {
|
||||
return [200, { data: v, code: 200 }]
|
||||
}
|
||||
@ -133,7 +133,7 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/video\/private/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
return [
|
||||
200,
|
||||
{
|
||||
@ -148,7 +148,7 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/video\/like/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
return [
|
||||
200,
|
||||
{
|
||||
@ -163,18 +163,18 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/video\/my/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
if (!userVideos.length) {
|
||||
// let r = await fetch(BASE_URL + '/data/user-71158770.json')
|
||||
// let r = await fetch(BASE_URL + '/data/user-8357999.json')
|
||||
let r = await fetch(BASE_URL + '/data/user_video_list/user-12345xiaolaohu.json')
|
||||
let list = await r.json()
|
||||
const r = await fetch(BASE_URL + '/data/user_video_list/user-12345xiaolaohu.json')
|
||||
const list = await r.json()
|
||||
const baseStore = useBaseStore()
|
||||
let userList = cloneDeep(baseStore.users)
|
||||
const userList = cloneDeep(baseStore.users)
|
||||
|
||||
userVideos = list.map((w) => {
|
||||
if (userList.length) {
|
||||
let item = userList.find((a) => String(a.uid) === String(w.author_user_id))
|
||||
const item = userList.find((a) => String(a.uid) === String(w.author_user_id))
|
||||
if (item) w.author = item
|
||||
}
|
||||
return w
|
||||
@ -196,7 +196,7 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/video\/history/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
return [
|
||||
200,
|
||||
{
|
||||
@ -231,9 +231,9 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/user\/video_list/).reply(async (config) => {
|
||||
let id = config.params.id
|
||||
let r2 = await fetch(`${FILE_URL}/user_video_list/user-${id}.json`)
|
||||
let v = await r2.json()
|
||||
const id = config.params.id
|
||||
const r2 = await fetch(`${FILE_URL}/user_video_list/user-${id}.json`)
|
||||
const v = await r2.json()
|
||||
if (v) {
|
||||
return [200, { data: v, code: 200 }]
|
||||
}
|
||||
@ -241,11 +241,11 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/user\/panel/).reply(async () => {
|
||||
let r2 = await fetch(BASE_URL + '/data/users.json')
|
||||
let v = await r2.json()
|
||||
const r2 = await fetch(BASE_URL + '/data/users.json')
|
||||
const v = await r2.json()
|
||||
// let item = v.find(a => a.uid === '68310389333')
|
||||
// let item = v.find(a => a.uid === '59054327754')
|
||||
let item = v.find((a) => a.uid === '2739632844317827')
|
||||
const item = v.find((a) => a.uid === '2739632844317827')
|
||||
if (item) {
|
||||
return [200, { data: item, code: 200 }]
|
||||
}
|
||||
@ -253,13 +253,13 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/user\/friends/).reply(async () => {
|
||||
let r2 = await fetch(BASE_URL + '/data/users.json')
|
||||
let v = await r2.json()
|
||||
const r2 = await fetch(BASE_URL + '/data/users.json')
|
||||
const v = await r2.json()
|
||||
return [200, { data: v, code: 200 }]
|
||||
})
|
||||
|
||||
mock.onGet(/historyOther/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
return [
|
||||
200,
|
||||
{
|
||||
@ -275,10 +275,10 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/post\/recommended/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
|
||||
if (!allRecommendPosts.length) {
|
||||
let r = await fetch(BASE_URL + '/data/posts.json')
|
||||
const r = await fetch(BASE_URL + '/data/posts.json')
|
||||
allRecommendPosts = await r.json()
|
||||
}
|
||||
return [
|
||||
@ -296,10 +296,10 @@ export async function startMock() {
|
||||
})
|
||||
|
||||
mock.onGet(/shop\/recommended/).reply(async (config) => {
|
||||
let page = getPage2(config.params)
|
||||
const page = getPage2(config.params)
|
||||
|
||||
let r2 = await fetch(BASE_URL + '/data/goods.json')
|
||||
let v = await r2.json()
|
||||
const r2 = await fetch(BASE_URL + '/data/goods.json')
|
||||
const v = await r2.json()
|
||||
return [
|
||||
200,
|
||||
{
|
||||
@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<div id="Music">
|
||||
<div class="header">
|
||||
<dy-back mode="light" @click="$back" />
|
||||
<dy-back mode="light" @click="router.back()" />
|
||||
<transition name="fade">
|
||||
<div class="center" v-if="isFixed">
|
||||
<span class="f16">{{ music.name }}</span>
|
||||
<div class="center" v-if="data.isFixed">
|
||||
<span class="f16">{{ data.music.name }}</span>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="right">
|
||||
<!-- TODO 没有淡入淡出的特效-->
|
||||
<template v-if="isFixed">
|
||||
<template v-if="data.isFixed">
|
||||
<img
|
||||
class="star"
|
||||
v-if="isCollect"
|
||||
v-if="data.isCollect"
|
||||
src="../../assets/img/icon/star-yellow.png"
|
||||
@click.stop="toggleCollect()"
|
||||
/>
|
||||
@ -23,38 +23,54 @@
|
||||
@click.stop="toggleCollect()"
|
||||
/>
|
||||
</template>
|
||||
<div class="logo" v-if="!isFixed" @click="$nav('/home/music-rank-list')">抖音音乐榜</div>
|
||||
<img class="share" src="../../assets/img/icon/share-white.png" @click="isSharing = true" />
|
||||
<div class="logo" v-if="!data.isFixed" @click="nav('/home/music-rank-list')">
|
||||
抖音音乐榜
|
||||
</div>
|
||||
<img
|
||||
class="share"
|
||||
src="../../assets/img/icon/share-white.png"
|
||||
@click="data.isSharing = true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<Scroll
|
||||
class="Scroll"
|
||||
:fixedHeight="180"
|
||||
@fixed="(e) => (this.isFixed = e)"
|
||||
@fixed="(e) => (data.isFixed = e)"
|
||||
@pulldown="loadData"
|
||||
>
|
||||
<div class="desc">
|
||||
<div class="cover-wrapper" @click="togglePlay()">
|
||||
<img class="cover" :src="$imgPreview(music.cover)" alt="" />
|
||||
<img v-if="!isPlay" src="../../assets/img/icon/play-white.png" alt="" class="play" />
|
||||
<img v-if="isPlay" src="../../assets/img/icon/pause-white.png" alt="" class="play" />
|
||||
<img class="cover" :src="_checkImgUrl(data.music.cover)" alt="" />
|
||||
<img
|
||||
v-if="!data.isPlay"
|
||||
src="../../assets/img/icon/play-white.png"
|
||||
alt=""
|
||||
class="play"
|
||||
/>
|
||||
<img
|
||||
v-if="data.isPlay"
|
||||
src="../../assets/img/icon/pause-white.png"
|
||||
alt=""
|
||||
class="play"
|
||||
/>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name">{{ music.name }}</div>
|
||||
<div class="name">{{ data.music.name }}</div>
|
||||
<div>
|
||||
<div class="user">{{ music.author }}</div>
|
||||
<div class="peoples">{{ formatNumber(music.use_count) }} 人使用</div>
|
||||
<div class="user">{{ data.music.author }}</div>
|
||||
<div class="peoples">{{ _formatNumber(data.music.use_count) }} 人使用</div>
|
||||
</div>
|
||||
<div class="collection" @click.stop="toggleCollect()">
|
||||
<img v-if="isCollect" src="../../assets/img/icon/star-yellow.png" />
|
||||
<img v-if="data.isCollect" src="../../assets/img/icon/star-yellow.png" />
|
||||
<img v-else src="../../assets/img/icon/star-white.png" />
|
||||
<span>{{ isCollect ? '已' : '' }}收藏</span>
|
||||
<span>{{ data.isCollect ? '已' : '' }}收藏</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Posters mode="music" :list="videos" />
|
||||
<Loading :is-full-screen="false" v-if="loading" />
|
||||
<Posters mode="music" :list="data.videos" />
|
||||
<Loading :is-full-screen="false" v-if="data.loading" />
|
||||
<NoMore v-else />
|
||||
</Scroll>
|
||||
</div>
|
||||
@ -70,165 +86,161 @@
|
||||
</div>
|
||||
|
||||
<Share
|
||||
v-model="isSharing"
|
||||
v-model="data.isSharing"
|
||||
mode="music"
|
||||
ref="share"
|
||||
pageId="Music"
|
||||
@showDouyinCode="showDouyinCode = true"
|
||||
@showShare2WeChatZone="shareType = 2"
|
||||
@share2WeChat="shareType = 3"
|
||||
@share2QQZone="shareType = 4"
|
||||
@share2QQ="shareType = 5"
|
||||
@share2Webo="shareType = 8"
|
||||
@ShareToFriend="delayShowDialog((e) => (this.shareToFriend = true))"
|
||||
@showDouyinCode="data.showDouyinCode = true"
|
||||
@showShare2WeChatZone="data.shareType = 2"
|
||||
@share2WeChat="data.shareType = 3"
|
||||
@share2QQZone="data.shareType = 4"
|
||||
@share2QQ="data.shareType = 5"
|
||||
@share2Webo="data.shareType = 8"
|
||||
@ShareToFriend="delayShowDialog(() => (data.shareToFriend = true))"
|
||||
/>
|
||||
|
||||
<DouyinCode v-model="showDouyinCode" />
|
||||
<DouyinCode v-model="data.showDouyinCode" />
|
||||
|
||||
<ConfirmDialog
|
||||
v-model:visible="showSharePassword"
|
||||
v-model:visible="data.showSharePassword"
|
||||
title="你的口令已复制"
|
||||
subtitle="0F.:/ a【风就应该自由要什么归宿】长按复制此条消息,打开抖音搜索,聆听音乐##kwu3VCixHl8##[抖音口令]"
|
||||
:okText="okText"
|
||||
:okText="data.okText"
|
||||
cancelText="不分享了"
|
||||
@ok="shareType = -1"
|
||||
@cancel="shareType = -1"
|
||||
@ok="data.shareType = -1"
|
||||
@cancel="data.shareType = -1"
|
||||
>
|
||||
<template v-slot:header>
|
||||
<img style="width: 100%" src="../../assets/img/icon/share-password.webp" alt="" />
|
||||
</template>
|
||||
</ConfirmDialog>
|
||||
|
||||
<ShareToFriend pageId="Music" v-model="shareToFriend" />
|
||||
<ShareToFriend pageId="Music" v-model="data.shareToFriend" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Posters from '../../components/Posters'
|
||||
import Scroll from '../../components/Scroll'
|
||||
import Loading from '../../components/Loading'
|
||||
import Share from '../../components/Share'
|
||||
import DouyinCode from '../../components/DouyinCode'
|
||||
import ConfirmDialog from '../../components/dialog/ConfirmDialog'
|
||||
import ShareToFriend from './components/ShareToFriend'
|
||||
<script setup lang="ts">
|
||||
import Posters from '../../components/Posters.vue'
|
||||
import Scroll from '../../components/Scroll.vue'
|
||||
import Loading from '../../components/Loading.vue'
|
||||
import Share from '../../components/Share.vue'
|
||||
import DouyinCode from '../../components/DouyinCode.vue'
|
||||
import ConfirmDialog from '../../components/dialog/ConfirmDialog.vue'
|
||||
import ShareToFriend from './components/ShareToFriend.vue'
|
||||
import { myVideo } from '@/api/videos'
|
||||
import { onDeactivated, onMounted, onUnmounted, reactive, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
import { $no, $notice, _checkImgUrl, _formatNumber } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'Music',
|
||||
components: {
|
||||
Scroll,
|
||||
Posters,
|
||||
Loading,
|
||||
Share,
|
||||
DouyinCode,
|
||||
ConfirmDialog,
|
||||
ShareToFriend
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
isFixed: false,
|
||||
isCollect: false,
|
||||
isPlay: false,
|
||||
isSharing: false,
|
||||
okText: '',
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const nav = useNav()
|
||||
|
||||
showSharePassword: false,
|
||||
shareToFriend: false,
|
||||
shareType: -1,
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
isFixed: false,
|
||||
isCollect: false,
|
||||
isPlay: false,
|
||||
isSharing: false,
|
||||
okText: '',
|
||||
|
||||
showDouyinCode: false,
|
||||
audio: new Audio(),
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
pageSize: 15,
|
||||
videos: [],
|
||||
showSharePassword: false,
|
||||
shareToFriend: false,
|
||||
shareType: -1,
|
||||
|
||||
music: {
|
||||
name: '发如雪',
|
||||
mp3: 'https://m3.8js.net:99/2014/211204142150965.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
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
shareType(newVal) {
|
||||
if (newVal === -1) return
|
||||
this.showSharePassword = true
|
||||
switch (newVal) {
|
||||
case 2:
|
||||
case 3:
|
||||
return (this.okText = '去微信粘贴')
|
||||
case 4:
|
||||
case 5:
|
||||
return (this.okText = '去QQ粘贴')
|
||||
case 8:
|
||||
return (this.okText = '去微博粘贴')
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (this.$route.query.name) {
|
||||
this.music = this.$route.query
|
||||
}
|
||||
this.loadData(true)
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
toggleCollect() {
|
||||
this.isCollect = !this.isCollect
|
||||
},
|
||||
async loadData(init = false) {
|
||||
if (this.loading) return
|
||||
if (!init) {
|
||||
if (this.total <= this.videos.length) {
|
||||
return this.$notice('暂时没有更多了')
|
||||
}
|
||||
this.pageNo++
|
||||
}
|
||||
this.loading = true
|
||||
let res = await myVideo({
|
||||
pageNo: this.pageNo,
|
||||
pageSize: this.pageSize
|
||||
})
|
||||
this.loading = false
|
||||
if (res.code === this.SUCCESS) {
|
||||
this.videos = this.videos.concat(res.data.list)
|
||||
this.total = res.data.total
|
||||
}
|
||||
},
|
||||
togglePlay() {
|
||||
this.isPlay = !this.isPlay
|
||||
if (this.isPlay) {
|
||||
if (!this.audio.src) {
|
||||
this.audio.src = this.music.mp3
|
||||
}
|
||||
this.audio.play()
|
||||
this.audio.addEventListener('ended', () => (this.isPlay = false))
|
||||
} else {
|
||||
this.stopPlay()
|
||||
}
|
||||
},
|
||||
delayShowDialog(cb) {
|
||||
setTimeout(() => {
|
||||
cb()
|
||||
}, 100)
|
||||
},
|
||||
stopPlay() {
|
||||
this.audio.pause()
|
||||
this.audio.removeEventListener('ended', null)
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.stopPlay()
|
||||
},
|
||||
deactivated() {
|
||||
this.stopPlay()
|
||||
showDouyinCode: false,
|
||||
audio: new Audio(),
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
pageSize: 15,
|
||||
videos: [],
|
||||
|
||||
music: {
|
||||
name: '发如雪',
|
||||
mp3: 'https://m3.8js.net:99/2014/211204142150965.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
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => data.shareType,
|
||||
(newVal) => {
|
||||
if (newVal === -1) return
|
||||
data.showSharePassword = true
|
||||
switch (newVal) {
|
||||
case 2:
|
||||
case 3:
|
||||
return (data.okText = '去微信粘贴')
|
||||
case 4:
|
||||
case 5:
|
||||
return (data.okText = '去QQ粘贴')
|
||||
case 8:
|
||||
return (data.okText = '去微博粘贴')
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
if (route.query.name) {
|
||||
data.music = route.query as any
|
||||
}
|
||||
loadData(true)
|
||||
})
|
||||
|
||||
onUnmounted(stopPlay)
|
||||
onDeactivated(stopPlay)
|
||||
|
||||
function toggleCollect() {
|
||||
data.isCollect = !data.isCollect
|
||||
}
|
||||
|
||||
async function loadData(init = false) {
|
||||
if (data.loading) return
|
||||
if (!init) {
|
||||
if (data.total <= data.videos.length) {
|
||||
return $notice('暂时没有更多了')
|
||||
}
|
||||
data.pageNo++
|
||||
}
|
||||
data.loading = true
|
||||
let res: any = await myVideo({
|
||||
pageNo: data.pageNo,
|
||||
pageSize: data.pageSize
|
||||
})
|
||||
data.loading = false
|
||||
if (res.success) {
|
||||
data.videos = data.videos.concat(res.data.list)
|
||||
data.total = res.data.total
|
||||
}
|
||||
}
|
||||
|
||||
function togglePlay() {
|
||||
data.isPlay = !data.isPlay
|
||||
if (data.isPlay) {
|
||||
if (!data.audio.src) {
|
||||
data.audio.src = data.music.mp3
|
||||
}
|
||||
data.audio.play()
|
||||
data.audio.addEventListener('ended', () => (data.isPlay = false))
|
||||
} else {
|
||||
stopPlay()
|
||||
}
|
||||
}
|
||||
|
||||
function delayShowDialog(cb) {
|
||||
setTimeout(() => {
|
||||
cb()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
function stopPlay() {
|
||||
data.audio.pause()
|
||||
data.audio.removeEventListener('ended', null)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="MusicRankList" @scroll="scroll">
|
||||
<dy-back mode="light" img="back" @click="$back()" class="fixed-back" direction="left" />
|
||||
<dy-back mode="light" img="back" @click="router.back()" class="fixed-back" direction="left" />
|
||||
<div class="fixed-header" :style="fixedStyle">
|
||||
<span class="f16">抖音音乐榜</span>
|
||||
</div>
|
||||
@ -8,23 +8,23 @@
|
||||
<div class="content">
|
||||
<div class="l-header">
|
||||
<img src="../../assets/img/icon/music-rank-list.webp" alt="" />
|
||||
<div class="update-time">更新于:{{ $dateFormat(updateTime, 'D') }}</div>
|
||||
<div class="update-time">更新于:{{ _dateFormat(data.updateTime, 'D') }}</div>
|
||||
</div>
|
||||
<Indicator
|
||||
name="musicRankList"
|
||||
tabStyleWidth="33%"
|
||||
:tabTexts="['热歌榜', '飙升樘', '原创榜']"
|
||||
v-model:active-index="contentIndex"
|
||||
v-model:active-index="data.contentIndex"
|
||||
>
|
||||
</Indicator>
|
||||
<SlideHorizontal name="musicRankList" v-model:index="contentIndex">
|
||||
<SlideHorizontal name="musicRankList" v-model:index="data.contentIndex">
|
||||
<SlideItem>
|
||||
<div class="list">
|
||||
<div
|
||||
class="item"
|
||||
:key="index"
|
||||
v-for="(item, index) in hotList"
|
||||
@click="togglePlay(item, hotList)"
|
||||
v-for="(item, index) in data.hotList"
|
||||
@click="togglePlay(item, data.hotList)"
|
||||
>
|
||||
<div class="top">
|
||||
<div class="rank-wrapper">
|
||||
@ -51,7 +51,7 @@
|
||||
<div class="right">
|
||||
<div class="music">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover" />
|
||||
<img v-lazy="_checkImgUrl(item.cover)" alt="" class="cover" />
|
||||
<img
|
||||
v-if="!item.is_play"
|
||||
src="../../assets/img/icon/play-white.png"
|
||||
@ -70,9 +70,9 @@
|
||||
<div class="author">{{ item.author }}</div>
|
||||
<div class="desc-bottom">
|
||||
<div class="duration">
|
||||
{{ $duration(item.duration) }}
|
||||
{{ _duration(item.duration) }}
|
||||
</div>
|
||||
<div class="use_count">{{ formatNumber(item.use_count) }}人使用</div>
|
||||
<div class="use_count">{{ _formatNumber(item.use_count) }}人使用</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -92,7 +92,7 @@
|
||||
<img
|
||||
src="../../assets/img/icon/menu2-white.png"
|
||||
alt=""
|
||||
@click.stop="$nav('/home/music')"
|
||||
@click.stop="nav('/home/music')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -116,8 +116,8 @@
|
||||
<div
|
||||
class="item"
|
||||
:key="index"
|
||||
v-for="(item, index) in hotList"
|
||||
@click="togglePlay(item, hotList)"
|
||||
v-for="(item, index) in data.hotList"
|
||||
@click="togglePlay(item, data.hotList)"
|
||||
>
|
||||
<div class="top">
|
||||
<div class="rank-wrapper">
|
||||
@ -144,7 +144,7 @@
|
||||
<div class="right">
|
||||
<div class="music">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover" />
|
||||
<img v-lazy="_checkImgUrl(item.cover)" alt="" class="cover" />
|
||||
<img
|
||||
v-if="!item.is_play"
|
||||
src="../../assets/img/icon/play-white.png"
|
||||
@ -163,9 +163,9 @@
|
||||
<div class="author">{{ item.author }}</div>
|
||||
<div class="desc-bottom">
|
||||
<div class="duration">
|
||||
{{ $duration(item.duration) }}
|
||||
{{ _duration(item.duration) }}
|
||||
</div>
|
||||
<div class="use_count">{{ formatNumber(item.use_count) }}人使用</div>
|
||||
<div class="use_count">{{ _formatNumber(item.use_count) }}人使用</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -185,7 +185,7 @@
|
||||
<img
|
||||
src="../../assets/img/icon/menu2-white.png"
|
||||
alt=""
|
||||
@click.stop="$nav('/home/music')"
|
||||
@click.stop="nav('/home/music')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -209,8 +209,8 @@
|
||||
<div
|
||||
class="item"
|
||||
:key="index"
|
||||
v-for="(item, index) in hotList"
|
||||
@click="togglePlay(item, hotList)"
|
||||
v-for="(item, index) in data.hotList"
|
||||
@click="togglePlay(item, data.hotList)"
|
||||
>
|
||||
<div class="top">
|
||||
<div class="rank-wrapper">
|
||||
@ -237,7 +237,7 @@
|
||||
<div class="right">
|
||||
<div class="music">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover" />
|
||||
<img v-lazy="_checkImgUrl(item.cover)" alt="" class="cover" />
|
||||
<img
|
||||
v-if="!item.is_play"
|
||||
src="../../assets/img/icon/play-white.png"
|
||||
@ -256,9 +256,9 @@
|
||||
<div class="author">{{ item.author }}</div>
|
||||
<div class="desc-bottom">
|
||||
<div class="duration">
|
||||
{{ $duration(item.duration) }}
|
||||
{{ _duration(item.duration) }}
|
||||
</div>
|
||||
<div class="use_count">{{ formatNumber(item.use_count) }}人使用</div>
|
||||
<div class="use_count">{{ _formatNumber(item.use_count) }}人使用</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -278,7 +278,7 @@
|
||||
<img
|
||||
src="../../assets/img/icon/menu2-white.png"
|
||||
alt=""
|
||||
@click.stop="$nav('/home/music')"
|
||||
@click.stop="nav('/home/music')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -301,255 +301,258 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'MusicRankList',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
contentIndex: 0,
|
||||
hotList: [
|
||||
{
|
||||
name: '龙卷风',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/5605.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/1.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 99,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '爱在西元前',
|
||||
mp3: 'https://m3.8js.net:99/1916/501204165042405.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/2.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '蜗牛',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/3684.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/3.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '半岛铁盒',
|
||||
mp3: 'https://m3.8js.net:99/2016n/46/94745.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/4.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '轨迹',
|
||||
mp3: 'https://m3.8js.net:99/1832/411204324135934.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/5.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '七里香',
|
||||
mp3: 'https://m3.8js.net:99/2016n/14/53717.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/6.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '发如雪',
|
||||
mp3: 'https://m3.8js.net:99/2014/211204142150965.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
|
||||
},
|
||||
{
|
||||
name: '霍元甲',
|
||||
mp3: 'https://m3.8js.net:99/1921/261204212643140.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/8.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '千里之外(周杰伦/费玉清)',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/121.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/9.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '菊花台',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/2022.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/10.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '不能说的秘密',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/165.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/11.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '牛仔很忙',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/219.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/12.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '给我一首歌的时间',
|
||||
mp3: 'https://m3.8js.net:99/1938/041204380445445.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/13.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '烟花易冷',
|
||||
mp3: 'https://m3.8js.net:99/1828/051204280535192.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/14.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '惊叹号',
|
||||
mp3: 'https://m3.8js.net:99/20111103/150.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/15.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '明明就',
|
||||
mp3: 'https://m3.8js.net:99/2016n/27/96537.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/16.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '算什么男人',
|
||||
mp3: 'https://m3.8js.net:99/20150107/429.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/17.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '告白气球',
|
||||
mp3: 'https://m3.8js.net:99/20161016/481.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/18.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
}
|
||||
],
|
||||
updateTime: Date.now(),
|
||||
audio: new Audio(),
|
||||
scrollTop: -1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fixedStyle() {
|
||||
return {
|
||||
opacity: this.scrollTop / 120 > 1 ? 1 : this.scrollTop / 120
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.hotList = this.hotList.concat(this.hotList).concat(this.hotList).concat(this.hotList)
|
||||
this.hotList = this.hotList.slice(0, 50)
|
||||
},
|
||||
methods: {
|
||||
scroll(e) {
|
||||
this.scrollTop = e.target.scrollTop
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed, onDeactivated, onMounted, onUnmounted, reactive } from 'vue'
|
||||
import { $notice, _checkImgUrl, _dateFormat, _duration, _formatNumber } from '@/utils/index.jsx'
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
|
||||
defineOptions({
|
||||
name: 'MusicRankList'
|
||||
})
|
||||
const router = useRouter()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
contentIndex: 0,
|
||||
hotList: [
|
||||
{
|
||||
name: '龙卷风',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/5605.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/1.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 99,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
toggleCollect(item) {
|
||||
item.is_collect = !item.is_collect
|
||||
if (item.is_collect) {
|
||||
this.$notice('收藏成功')
|
||||
} else {
|
||||
this.$notice('取消收藏')
|
||||
}
|
||||
{
|
||||
name: '爱在西元前',
|
||||
mp3: 'https://m3.8js.net:99/1916/501204165042405.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/2.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
togglePlay(item, list) {
|
||||
list.map((v) => {
|
||||
if (v.name !== item.name) {
|
||||
v.is_play = false
|
||||
}
|
||||
})
|
||||
item.is_play = !item.is_play
|
||||
if (item.is_play) {
|
||||
this.audio.pause()
|
||||
this.audio.src = item.mp3
|
||||
this.audio.currentTime = 0
|
||||
this.audio.play()
|
||||
this.audio.addEventListener('ended', () => (item.is_play = false))
|
||||
} else {
|
||||
this.stopPlay()
|
||||
}
|
||||
{
|
||||
name: '蜗牛',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/3684.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/3.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
stopPlay() {
|
||||
this.audio.pause()
|
||||
this.audio.currentTime = 0
|
||||
this.audio.removeEventListener('ended', null)
|
||||
{
|
||||
name: '半岛铁盒',
|
||||
mp3: 'https://m3.8js.net:99/2016n/46/94745.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/4.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '轨迹',
|
||||
mp3: 'https://m3.8js.net:99/1832/411204324135934.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/5.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '七里香',
|
||||
mp3: 'https://m3.8js.net:99/2016n/14/53717.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/6.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '发如雪',
|
||||
mp3: 'https://m3.8js.net:99/2014/211204142150965.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
|
||||
},
|
||||
{
|
||||
name: '霍元甲',
|
||||
mp3: 'https://m3.8js.net:99/1921/261204212643140.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/8.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '千里之外(周杰伦/费玉清)',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/121.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/9.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '菊花台',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/2022.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/10.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '不能说的秘密',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/165.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/11.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '牛仔很忙',
|
||||
mp3: 'http://im5.tongbu.com/rings/singerring/zt_uunGo_1/219.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/12.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '给我一首歌的时间',
|
||||
mp3: 'https://m3.8js.net:99/1938/041204380445445.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/13.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '烟花易冷',
|
||||
mp3: 'https://m3.8js.net:99/1828/051204280535192.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/14.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '惊叹号',
|
||||
mp3: 'https://m3.8js.net:99/20111103/150.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/15.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '明明就',
|
||||
mp3: 'https://m3.8js.net:99/2016n/27/96537.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/16.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '算什么男人',
|
||||
mp3: 'https://m3.8js.net:99/20150107/429.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/17.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
},
|
||||
{
|
||||
name: '告白气球',
|
||||
mp3: 'https://m3.8js.net:99/20161016/481.mp3',
|
||||
cover: new URL('../../assets/img/music-cover/18.jpg', import.meta.url).href,
|
||||
author: '周杰伦',
|
||||
duration: 60,
|
||||
use_count: 37441000,
|
||||
is_collect: false,
|
||||
is_play: false
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.stopPlay()
|
||||
},
|
||||
deactivated() {
|
||||
this.stopPlay()
|
||||
],
|
||||
updateTime: Date.now(),
|
||||
audio: new Audio(),
|
||||
scrollTop: -1
|
||||
})
|
||||
|
||||
const fixedStyle = computed(() => {
|
||||
return {
|
||||
opacity: data.scrollTop / 120 > 1 ? 1 : data.scrollTop / 120
|
||||
}
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
data.hotList = data.hotList.concat(data.hotList).concat(data.hotList).concat(data.hotList)
|
||||
data.hotList = data.hotList.slice(0, 50)
|
||||
})
|
||||
|
||||
onUnmounted(stopPlay)
|
||||
onDeactivated(stopPlay)
|
||||
|
||||
function scroll(e) {
|
||||
data.scrollTop = e.target.scrollTop
|
||||
}
|
||||
|
||||
function toggleCollect(item) {
|
||||
item.is_collect = !item.is_collect
|
||||
if (item.is_collect) {
|
||||
$notice('收藏成功')
|
||||
} else {
|
||||
$notice('取消收藏')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
function togglePlay(item, list) {
|
||||
list.map((v) => {
|
||||
if (v.name !== item.name) {
|
||||
v.is_play = false
|
||||
}
|
||||
})
|
||||
item.is_play = !item.is_play
|
||||
if (item.is_play) {
|
||||
data.audio.pause()
|
||||
data.audio.src = item.mp3
|
||||
data.audio.currentTime = 0
|
||||
data.audio.play()
|
||||
data.audio.addEventListener('ended', () => (item.is_play = false))
|
||||
} else {
|
||||
data.stopPlay()
|
||||
}
|
||||
}
|
||||
|
||||
function stopPlay() {
|
||||
data.audio.pause()
|
||||
data.audio.currentTime = 0
|
||||
data.audio.removeEventListener('ended', null)
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
@import '../../assets/less/index';
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="Publish">
|
||||
<video id="video" autoplay="autoplay" style="width: 100%; height: calc(100% - 60rem)"></video>
|
||||
<video id="video" autoplay style="width: 100%; height: calc(100% - 60rem)"></video>
|
||||
<div class="footer">
|
||||
<SlideHorizontal style="height: 60rem" v-model:index="activeIndex">
|
||||
<SlideItem style="width: 20vw"></SlideItem>
|
||||
@ -20,7 +20,7 @@
|
||||
</SlideHorizontal>
|
||||
</div>
|
||||
<div class="float">
|
||||
<Icon class="close" icon="mingcute:close-line" @click="$back" />
|
||||
<Icon class="close" icon="mingcute:close-line" @click="router.back()" />
|
||||
<div class="choose-music">
|
||||
<Icon icon="vaadin:music" />
|
||||
<span>选择音乐</span>
|
||||
@ -48,9 +48,16 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'Publish'
|
||||
})
|
||||
const router = useRouter()
|
||||
const videoEl = ref(null)
|
||||
const activeIndex = ref(1)
|
||||
|
||||
//访问用户媒体设备的兼容方法
|
||||
function getUserMedia(constrains, success, error) {
|
||||
@ -63,51 +70,37 @@ function getUserMedia(constrains, success, error) {
|
||||
} else if (navigator.mozGetUserMedia) {
|
||||
//Firefox浏览器
|
||||
// eslint-disable-next-line no-undef
|
||||
navagator.mozGetUserMedia(constrains).then(success).catch(error)
|
||||
navigator.mozGetUserMedia(constrains).then(success).catch(error)
|
||||
} else if (navigator.getUserMedia) {
|
||||
//旧版API
|
||||
navigator.getUserMedia(constrains).then(success).catch(error)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'Publish',
|
||||
data() {
|
||||
return {
|
||||
video: null,
|
||||
activeIndex: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['bodyHeight', 'bodyWidth'])
|
||||
},
|
||||
mounted() {
|
||||
//获得video摄像头区域
|
||||
this.video = document.getElementById('video')
|
||||
this.getMedia()
|
||||
},
|
||||
methods: {
|
||||
getMedia() {
|
||||
// let constraints = {video: {width: this.bodyWidth, height: this.bodyHeight - 60}, audio: false};
|
||||
// let constraints = {video:{width:480,height:320}, audio: false};
|
||||
let constraints = { video: true, audio: false }
|
||||
try {
|
||||
getUserMedia(
|
||||
constraints,
|
||||
(MediaStream) => {
|
||||
this.video.srcObject = MediaStream
|
||||
this.video.play()
|
||||
},
|
||||
function (PermissionDeniedError) {
|
||||
console.log(PermissionDeniedError)
|
||||
}
|
||||
)
|
||||
} catch (e) {
|
||||
console.log('e', e)
|
||||
function getMedia() {
|
||||
// let constraints = {video: {width: this.bodyWidth, height: this.bodyHeight - 60}, audio: false};
|
||||
// let constraints = {video:{width:480,height:320}, audio: false};
|
||||
let constraints = { video: true, audio: false }
|
||||
try {
|
||||
getUserMedia(
|
||||
constraints,
|
||||
(MediaStream) => {
|
||||
videoEl.value.srcObject = MediaStream
|
||||
videoEl.value.play()
|
||||
},
|
||||
function (PermissionDeniedError) {
|
||||
console.log(PermissionDeniedError)
|
||||
}
|
||||
}
|
||||
)
|
||||
} catch (e) {
|
||||
console.log('e', e)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
videoEl.value = document.getElementById('video')
|
||||
getMedia()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -160,7 +160,7 @@
|
||||
:videoId="state.recommendList[state.itemIndex]?.id"
|
||||
:canDownload="state.recommendList[state.itemIndex]?.canDownload"
|
||||
@play-feedback="state.showPlayFeedback = true"
|
||||
@shareToFriend="delayShowDialog((e) => (state.shareToFriend = true))"
|
||||
@shareToFriend="delayShowDialog(() => (state.shareToFriend = true))"
|
||||
@showDouyinCode="state.showDouyinCode = true"
|
||||
@download="state.shareType = 9"
|
||||
/>
|
||||
@ -185,7 +185,7 @@
|
||||
|
||||
<FollowSetting2
|
||||
v-model:currentItem="state.currentItem"
|
||||
@cancelFollow="$refs.uploader.cancelFollow()"
|
||||
@cancelFollow="uploader.cancelFollow()"
|
||||
v-model="state.showFollowSetting2"
|
||||
/>
|
||||
|
||||
@ -199,13 +199,13 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
<script setup lang="tsx">
|
||||
import SlideHorizontal from '@/components/slide/SlideHorizontal.vue'
|
||||
import SlideItem from '@/components/slide/SlideItem.vue'
|
||||
import Comment from '../../components/Comment.vue'
|
||||
import Share from '../../components/Share.vue'
|
||||
import IndicatorHome from './components/IndicatorHome.vue'
|
||||
import { onActivated, onDeactivated, onMounted, onUnmounted, reactive } from 'vue'
|
||||
import { onActivated, onDeactivated, onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
import bus, { EVENT_KEY } from '../../utils/bus'
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
import PlayFeedback from '@/pages/home/components/PlayFeedback.vue'
|
||||
@ -229,11 +229,13 @@ import { useBaseStore } from '@/store/pinia'
|
||||
|
||||
const nav = useNav()
|
||||
const baseStore = useBaseStore()
|
||||
const uploader = ref()
|
||||
|
||||
const state = reactive({
|
||||
active: true,
|
||||
baseIndex: 1,
|
||||
navIndex: 4,
|
||||
itemIndex: 0,
|
||||
test: '',
|
||||
recommendList: [],
|
||||
isSharing: false,
|
||||
@ -253,13 +255,14 @@ const state = reactive({
|
||||
commentVisible: false,
|
||||
fullScreen: false,
|
||||
currentItem: {
|
||||
aweme_id: '',
|
||||
author: DefaultUser,
|
||||
isRequest: false,
|
||||
aweme_list: []
|
||||
}
|
||||
})
|
||||
|
||||
function delayShowDialog(cb) {
|
||||
function delayShowDialog(cb: Function) {
|
||||
setTimeout(cb, 400)
|
||||
}
|
||||
|
||||
|
||||
@ -1,14 +1,18 @@
|
||||
<template>
|
||||
<div id="MyCard">
|
||||
<div class="header">
|
||||
<dy-back mode="light" @click="$back" />
|
||||
<dy-back mode="light" @click="router.back" />
|
||||
<!-- todo 差一-->
|
||||
<img class="share" src="../../assets/img/icon/share-white.png" @click="isSharing = true" />
|
||||
<img
|
||||
class="share"
|
||||
src="../../assets/img/icon/share-white.png"
|
||||
@click="data.isSharing = true"
|
||||
/>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="qrcode">
|
||||
<img class="qrcode-bg" src="../../assets/img/icon/me/code-bg.png" alt="" />
|
||||
<img class="avatar" :src="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" />
|
||||
<img class="avatar" :src="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])" alt="" />
|
||||
</div>
|
||||
|
||||
<span class="name">ZZZZZZZZZZ</span>
|
||||
@ -30,65 +34,52 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Share v-model="isSharing" mode="qrcode" ref="share" page-id="MyCard" />
|
||||
<Share v-model:value="data.isSharing" mode="qrcode" ref="share" page-id="MyCard" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Share from '../../components/Share'
|
||||
import { mapState } from 'pinia'
|
||||
|
||||
<script setup lang="ts">
|
||||
import Share from '../../components/Share.vue'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { _checkImgUrl } from '@/utils'
|
||||
import { $no, _checkImgUrl } from '@/utils'
|
||||
import { reactive, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'MyCard',
|
||||
components: {
|
||||
Share
|
||||
},
|
||||
defineOptions({
|
||||
name: 'MyCard'
|
||||
})
|
||||
|
||||
data() {
|
||||
return {
|
||||
isSharing: false,
|
||||
okText: '',
|
||||
const router = useRouter()
|
||||
const store = useBaseStore()
|
||||
const data = reactive({
|
||||
isSharing: false,
|
||||
okText: '',
|
||||
showSharePassword: false,
|
||||
shareToFriend: false,
|
||||
shareType: -1,
|
||||
showDouyinCode: false
|
||||
})
|
||||
|
||||
showSharePassword: false,
|
||||
shareToFriend: false,
|
||||
shareType: -1,
|
||||
|
||||
showDouyinCode: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
shareType(newVal) {
|
||||
if (newVal === -1) return
|
||||
this.showSharePassword = true
|
||||
switch (newVal) {
|
||||
case 2:
|
||||
case 3:
|
||||
return (this.okText = '去微信粘贴')
|
||||
case 4:
|
||||
case 5:
|
||||
return (this.okText = '去QQ粘贴')
|
||||
case 8:
|
||||
return (this.okText = '去微博粘贴')
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['userinfo'])
|
||||
},
|
||||
methods: {
|
||||
_checkImgUrl,
|
||||
delayShowDialog(cb) {
|
||||
setTimeout(() => {
|
||||
cb()
|
||||
}, 100)
|
||||
watch(
|
||||
() => data.shareType,
|
||||
(newVal) => {
|
||||
if (newVal === -1) return
|
||||
data.showSharePassword = true
|
||||
switch (newVal) {
|
||||
case 2:
|
||||
case 3:
|
||||
return (data.okText = '去微信粘贴')
|
||||
case 4:
|
||||
case 5:
|
||||
return (data.okText = '去QQ粘贴')
|
||||
case 8:
|
||||
return (data.okText = '去微博粘贴')
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
<style lang="less" scoped>
|
||||
@import '../../assets/less/index';
|
||||
|
||||
#MyCard {
|
||||
|
||||
@ -9,13 +9,13 @@
|
||||
<div class="list">
|
||||
<div
|
||||
class="item"
|
||||
v-for="(item, index) in list"
|
||||
v-for="(item, index) in data.list"
|
||||
:key="index"
|
||||
@click="togglePlay(item, list)"
|
||||
@click="togglePlay(item, data.list)"
|
||||
>
|
||||
<div class="music">
|
||||
<div class="cover-wrapper">
|
||||
<img v-lazy="$imgPreview(item.cover)" alt="" class="cover" />
|
||||
<img v-lazy="_checkImgUrl(item.cover)" alt="" class="cover" />
|
||||
<img
|
||||
v-if="!item.is_play"
|
||||
src="@/assets/img/icon/play-white.png"
|
||||
@ -33,7 +33,7 @@
|
||||
<span class="name">{{ item.name }}</span>
|
||||
<div class="author">{{ item.author }}</div>
|
||||
<div class="desc-bottom">
|
||||
<div class="duration">{{ $duration(item.duration) }}</div>
|
||||
<div class="duration">{{ _duration(item.duration) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -41,126 +41,124 @@
|
||||
<img
|
||||
src="@/assets/img/icon/menu2-white.png"
|
||||
alt=""
|
||||
@click.stop="$nav('/home/music', item)"
|
||||
@click.stop="nav('/home/music', item)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Loading v-if="loading" :is-full-screen="false" />
|
||||
<Loading v-if="data.loading" :is-full-screen="false" />
|
||||
<no-more v-else class="mb7r" />
|
||||
</div>
|
||||
<div class="float-play-music" v-if="currentItem">
|
||||
<div class="process" :style="{ width: process + 'px' }"></div>
|
||||
<div class="float-play-music" v-if="data.currentItem">
|
||||
<div class="process" :style="{ width: data.process + 'px' }"></div>
|
||||
<div class="music-wrapper">
|
||||
<div class="music">
|
||||
<div class="cover-wrapper" @click="togglePlay(currentItem, list)">
|
||||
<img v-lazy="$imgPreview(currentItem.cover)" alt="" class="cover" />
|
||||
<div class="cover-wrapper" @click="togglePlay(data.currentItem, data.list)">
|
||||
<img v-lazy="_checkImgUrl(data.currentItem.cover)" alt="" class="cover" />
|
||||
<img
|
||||
v-if="!currentItem.is_play"
|
||||
v-if="!data.currentItem.is_play"
|
||||
src="@/assets/img/icon/play-white.png"
|
||||
alt=""
|
||||
class="play"
|
||||
/>
|
||||
<img
|
||||
v-if="currentItem.is_play"
|
||||
v-if="data.currentItem.is_play"
|
||||
src="@/assets/img/icon/pause-white.png"
|
||||
alt=""
|
||||
class="play"
|
||||
/>
|
||||
</div>
|
||||
<div class="desc">
|
||||
<span class="name">{{ currentItem.name }}</span>
|
||||
<span class="name">{{ data.currentItem.name }}</span>
|
||||
<div class="desc-bottom">
|
||||
<div class="duration">{{ $duration(currentItem.duration) }}</div>
|
||||
<div class="duration">{{ _duration(data.currentItem.duration) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option">
|
||||
<dy-button type="primary" size="small" @click="$no">使用</dy-button>
|
||||
<dy-button type="primary" size="small" @click="_no">使用</dy-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
<script setup lang="ts">
|
||||
import { userCollect } from '@/api/user'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
|
||||
export default {
|
||||
name: 'MusicCollect',
|
||||
components: {},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
list: [],
|
||||
audio: new Audio(),
|
||||
currentItem: null,
|
||||
step: null,
|
||||
process: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['bodyWidth'])
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
mounted() {
|
||||
this.audio.addEventListener('loadedmetadata', () => {
|
||||
this.currentItem.duration = this.audio.duration
|
||||
this.step = this.bodyWidth / Math.floor(this.audio.duration)
|
||||
})
|
||||
this.audio.addEventListener('timeupdate', (e) => {
|
||||
this.process = Math.ceil(e.target.currentTime) * this.step
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
async getData() {
|
||||
this.loading = true
|
||||
let res = await userCollect()
|
||||
this.loading = false
|
||||
if (res.code === this.SUCCESS) {
|
||||
this.list = res.data.music.list
|
||||
}
|
||||
},
|
||||
togglePlay(item, list) {
|
||||
list.map((v) => {
|
||||
if (v.name !== item.name) {
|
||||
v.is_play = false
|
||||
}
|
||||
})
|
||||
item.is_play = !item.is_play
|
||||
if (item.is_play) {
|
||||
if (this.currentItem) {
|
||||
if (this.currentItem.name !== item.name) {
|
||||
this.audio.pause()
|
||||
this.audio.src = item.mp3
|
||||
this.audio.currentTime = 0
|
||||
}
|
||||
} else {
|
||||
this.audio.pause()
|
||||
this.audio.src = item.mp3
|
||||
this.audio.currentTime = 0
|
||||
}
|
||||
this.audio.play()
|
||||
this.audio.addEventListener('ended', () => (item.is_play = false))
|
||||
} else {
|
||||
this.stopPlay()
|
||||
}
|
||||
this.currentItem = item
|
||||
},
|
||||
stopPlay() {
|
||||
this.audio.pause()
|
||||
// this.audio.currentTime = 0
|
||||
this.audio.removeEventListener('ended', null)
|
||||
}
|
||||
},
|
||||
unmounted() {
|
||||
this.stopPlay()
|
||||
import { onMounted, onUnmounted, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { _checkImgUrl, _duration, _no } from '@/utils'
|
||||
|
||||
defineOptions({
|
||||
name: 'MusicCollect'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
list: [],
|
||||
audio: new Audio(),
|
||||
currentItem: null,
|
||||
step: null,
|
||||
process: 0
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
data.audio.addEventListener('loadedmetadata', () => {
|
||||
data.currentItem.duration = data.audio.duration
|
||||
data.step = store.bodyWidth / Math.floor(data.audio.duration)
|
||||
})
|
||||
data.audio.addEventListener('timeupdate', (e: any) => {
|
||||
data.process = Math.ceil(e.target.currentTime) * data.step
|
||||
})
|
||||
})
|
||||
|
||||
onUnmounted(stopPlay)
|
||||
|
||||
async function getData() {
|
||||
data.loading = true
|
||||
let res: any = await userCollect()
|
||||
data.loading = false
|
||||
if (res.success) {
|
||||
data.list = res.data.music.list
|
||||
}
|
||||
}
|
||||
|
||||
function togglePlay(item, list) {
|
||||
list.map((v) => {
|
||||
if (v.name !== item.name) {
|
||||
v.is_play = false
|
||||
}
|
||||
})
|
||||
item.is_play = !item.is_play
|
||||
if (item.is_play) {
|
||||
if (data.currentItem) {
|
||||
if (data.currentItem.name !== item.name) {
|
||||
data.audio.pause()
|
||||
data.audio.src = item.mp3
|
||||
data.audio.currentTime = 0
|
||||
}
|
||||
} else {
|
||||
data.audio.pause()
|
||||
data.audio.src = item.mp3
|
||||
data.audio.currentTime = 0
|
||||
}
|
||||
data.audio.play()
|
||||
data.audio.addEventListener('ended', () => (item.is_play = false))
|
||||
} else {
|
||||
stopPlay()
|
||||
}
|
||||
data.currentItem = item
|
||||
}
|
||||
|
||||
function stopPlay() {
|
||||
data.audio.pause()
|
||||
// data.audio.currentTime = 0
|
||||
data.audio.removeEventListener('ended', null)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -7,63 +7,59 @@
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<Scroll class="Scroll" @pulldown="loadData">
|
||||
<Posters mode="music" :list="videos" />
|
||||
<Loading :is-full-screen="false" v-if="loading" />
|
||||
<Posters mode="music" :list="data.videos" />
|
||||
<Loading :is-full-screen="false" v-if="data.loading" />
|
||||
<NoMore v-else />
|
||||
</Scroll>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Posters from '../../../components/Posters'
|
||||
import Scroll from '../../../components/Scroll'
|
||||
<script setup lang="ts">
|
||||
import Posters from '@/components/Posters.vue'
|
||||
import Scroll from '@/components/Scroll.vue'
|
||||
import { myVideo } from '@/api/videos'
|
||||
|
||||
export default {
|
||||
name: 'VideoCollect',
|
||||
components: {
|
||||
Posters,
|
||||
Scroll
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
pageSize: 15,
|
||||
videos: []
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.loadData(true)
|
||||
},
|
||||
methods: {
|
||||
async loadData(init = false) {
|
||||
if (this.loading) return
|
||||
if (!init) {
|
||||
if (this.total <= this.videos.length) {
|
||||
return
|
||||
}
|
||||
this.pageNo++
|
||||
}
|
||||
this.loading = true
|
||||
let res = await myVideo({
|
||||
pageNo: this.pageNo,
|
||||
pageSize: this.pageSize
|
||||
})
|
||||
this.loading = false
|
||||
if (res.code === this.SUCCESS) {
|
||||
this.videos = this.videos.concat(res.data.list)
|
||||
this.total = res.data.total
|
||||
}
|
||||
import { onMounted, reactive } from 'vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'VideoCollect'
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
pageSize: 15,
|
||||
videos: []
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
loadData(true)
|
||||
})
|
||||
|
||||
async function loadData(init = false) {
|
||||
if (data.loading) return
|
||||
if (!init) {
|
||||
if (data.total <= data.videos.length) {
|
||||
return
|
||||
}
|
||||
data.pageNo++
|
||||
}
|
||||
data.loading = true
|
||||
let res: any = await myVideo({
|
||||
pageNo: data.pageNo,
|
||||
pageSize: data.pageSize
|
||||
})
|
||||
data.loading = false
|
||||
if (res.success) {
|
||||
data.videos = data.videos.concat(res.data.list)
|
||||
data.total = res.data.total
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../../../assets/less/index';
|
||||
@import '@/assets/less/index';
|
||||
|
||||
.VideoCollect {
|
||||
position: fixed;
|
||||
|
||||
@ -13,16 +13,16 @@
|
||||
style="width: calc(100vw - 2rem); margin-left: 1rem"
|
||||
tabStyleWidth="50%"
|
||||
:tabTexts="['视频', '影视综']"
|
||||
v-model:active-index="currentSlideItemIndex"
|
||||
v-model:active-index="data.currentSlideItemIndex"
|
||||
>
|
||||
</Indicator>
|
||||
<SlideHorizontal v-model:index="currentSlideItemIndex" class="SlideRowList">
|
||||
<SlideHorizontal v-model:index="data.currentSlideItemIndex" class="SlideRowList">
|
||||
<SlideItem class="tab1" style="overflow: auto">
|
||||
<Scroll class="Scroll" @pulldown="getHistoryVideo">
|
||||
<Posters :list="historyVideo.list" v-if="historyVideo.total"></Posters>
|
||||
<Loading :is-full-screen="false" v-if="loadingVideo" />
|
||||
<Posters :list="data.historyVideo.list" v-if="data.historyVideo.total"></Posters>
|
||||
<Loading :is-full-screen="false" v-if="data.loadingVideo" />
|
||||
<template v-else>
|
||||
<NoMore v-if="historyVideo.list.length" />
|
||||
<NoMore v-if="data.historyVideo.list.length" />
|
||||
<div class="empty" v-else>
|
||||
<img src="../../../assets/img/icon/none-bg1.webp" alt="" />
|
||||
<div class="title">暂无观看历史记录</div>
|
||||
@ -40,100 +40,97 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Posters from '../../../components/Posters'
|
||||
import Scroll from '../../../components/Scroll'
|
||||
import NoMore from '../../../components/NoMore'
|
||||
<script setup lang="ts">
|
||||
import Posters from '@/components/Posters.vue'
|
||||
import Scroll from '@/components/Scroll.vue'
|
||||
import NoMore from '@/components/NoMore.vue'
|
||||
import { historyOther, historyVideo } from '@/api/videos'
|
||||
|
||||
export default {
|
||||
name: 'lookHistory',
|
||||
components: {
|
||||
NoMore,
|
||||
Posters,
|
||||
Scroll
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import { _showConfirmDialog } from '@/utils'
|
||||
|
||||
defineOptions({
|
||||
name: 'LookHistory'
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
loadingVideo: false,
|
||||
loadingOther: false,
|
||||
isClearHistoryVideo: false,
|
||||
isClearHistoryOther: false,
|
||||
currentSlideItemIndex: 0,
|
||||
pageSize: 15,
|
||||
historyVideo: {
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
list: []
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loadingVideo: false,
|
||||
loadingOther: false,
|
||||
isClearHistoryVideo: false,
|
||||
isClearHistoryOther: false,
|
||||
currentSlideItemIndex: 0,
|
||||
pageSize: 15,
|
||||
historyVideo: {
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
list: []
|
||||
},
|
||||
historyOther: {
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
list: []
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isClear() {
|
||||
if (this.currentSlideItemIndex === 0) {
|
||||
return this.historyVideo.list.length
|
||||
}
|
||||
return this.historyOther.list.length
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getHistoryVideo(true)
|
||||
this.getHistoryOther(true)
|
||||
},
|
||||
methods: {
|
||||
async getHistoryVideo(init = false) {
|
||||
if (this.loadingVideo) return
|
||||
if (this.isClearHistoryVideo) return
|
||||
if (!init) {
|
||||
if (this.historyVideo.total <= this.historyVideo.list.length) return
|
||||
this.historyVideo.pageNo++
|
||||
}
|
||||
this.loadingVideo = true
|
||||
let res = await historyVideo({
|
||||
pageNo: this.historyVideo.pageNo,
|
||||
pageSize: this.pageSize
|
||||
})
|
||||
console.log(res)
|
||||
this.loadingVideo = false
|
||||
if (res.code === this.SUCCESS) {
|
||||
this.historyVideo.list = this.historyVideo.list.concat(res.data.list)
|
||||
this.historyVideo.total = res.data.total
|
||||
}
|
||||
},
|
||||
async getHistoryOther(init = false) {
|
||||
if (this.loadingOther) return
|
||||
if (this.isClearHistoryOther) return
|
||||
this.loadingOther = true
|
||||
if (!init) {
|
||||
this.historyOther.pageNo++
|
||||
}
|
||||
let res = await historyOther({
|
||||
pageNo: this.historyOther.pageNo,
|
||||
pageSize: this.pageSize
|
||||
})
|
||||
this.loadingOther = false
|
||||
if (res.code === this.SUCCESS) {
|
||||
this.historyOther.list = this.historyOther.list.concat(res.data.list)
|
||||
this.historyOther.total = res.data.total
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
this.$showConfirmDialog('确定清空?', '清空后,以往观看记录不再展示', 'gray', () => {
|
||||
if (this.currentSlideItemIndex === 0) {
|
||||
this.historyVideo.list = []
|
||||
this.isClearHistoryVideo = true
|
||||
return
|
||||
}
|
||||
this.historyOther.list = []
|
||||
this.isClearHistoryVideo = true
|
||||
})
|
||||
}
|
||||
historyOther: {
|
||||
total: 0,
|
||||
pageNo: 0,
|
||||
list: []
|
||||
}
|
||||
})
|
||||
|
||||
const isClear = computed(() => {
|
||||
if (data.currentSlideItemIndex === 0) {
|
||||
return data.historyVideo.list.length
|
||||
}
|
||||
return data.historyOther.list.length
|
||||
})
|
||||
onMounted(() => {
|
||||
getHistoryVideo(true)
|
||||
getHistoryOther(true)
|
||||
})
|
||||
|
||||
async function getHistoryVideo(init = false) {
|
||||
if (data.loadingVideo) return
|
||||
if (data.isClearHistoryVideo) return
|
||||
if (!init) {
|
||||
if (data.historyVideo.total <= data.historyVideo.list.length) return
|
||||
data.historyVideo.pageNo++
|
||||
}
|
||||
data.loadingVideo = true
|
||||
let res: any = await historyVideo({
|
||||
pageNo: data.historyVideo.pageNo,
|
||||
pageSize: data.pageSize
|
||||
})
|
||||
console.log(res)
|
||||
data.loadingVideo = false
|
||||
if (res.success) {
|
||||
data.historyVideo.list = data.historyVideo.list.concat(res.data.list)
|
||||
data.historyVideo.total = res.data.total
|
||||
}
|
||||
}
|
||||
|
||||
async function getHistoryOther(init = false) {
|
||||
if (data.loadingOther) return
|
||||
if (data.isClearHistoryOther) return
|
||||
data.loadingOther = true
|
||||
if (!init) {
|
||||
data.historyOther.pageNo++
|
||||
}
|
||||
let res: any = await historyOther({
|
||||
pageNo: data.historyOther.pageNo,
|
||||
pageSize: data.pageSize
|
||||
})
|
||||
data.loadingOther = false
|
||||
if (res.success) {
|
||||
data.historyOther.list = data.historyOther.list.concat(res.data.list)
|
||||
data.historyOther.total = res.data.total
|
||||
}
|
||||
}
|
||||
|
||||
function clear() {
|
||||
_showConfirmDialog('确定清空?', '清空后,以往观看记录不再展示', 'gray', () => {
|
||||
if (data.currentSlideItemIndex === 0) {
|
||||
data.historyVideo.list = []
|
||||
data.isClearHistoryVideo = true
|
||||
return
|
||||
}
|
||||
data.historyOther.list = []
|
||||
data.isClearHistoryVideo = true
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
<template>
|
||||
<div class="DetailSetting">
|
||||
<BaseHeader />
|
||||
<div class="content type1" v-if="type === 0">
|
||||
<div class="content type1" v-if="data.type === 0">
|
||||
<div class="notice">
|
||||
<img src="../../../../assets/img/icon/newicon/left_menu/lock.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/lock.png" alt="" />
|
||||
<span>时间锁已关闭</span>
|
||||
</div>
|
||||
<div class="row mt1r no-active">
|
||||
<div class="left">
|
||||
<img src="../../../../assets/img/icon/newicon/left_menu/hourglass.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/hourglass.png" alt="" />
|
||||
<span>可为时间锁设置一个触发时间</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt1r no-active">
|
||||
<div class="left">
|
||||
<img src="../../../../assets/img/icon/newicon/left_menu/clock.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/clock.png" alt="" />
|
||||
<span>开启时间锁后,单日使用时长超过触发时间,需输入密码才能继续使用</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt1r mb1r no-active">
|
||||
<div class="left">
|
||||
<img src="../../../../assets/img/icon/newicon/left_menu/lock.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/lock.png" alt="" />
|
||||
<span>开启时间锁,需先设置独立密码;忘记密码后可通过申诉重置密码</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt1r mb1r" @click="$nav('trigger-time', { triggerTime })">
|
||||
<div class="row mt1r mb1r" @click="nav('trigger-time', { triggerTime: data.triggerTime })">
|
||||
<div class="left">
|
||||
<span>触发时间</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span>{{ triggerTime }}分钟</span>
|
||||
<span>{{ data.triggerTime }}分钟</span>
|
||||
<dy-back direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
@ -37,62 +37,62 @@
|
||||
<div class="button primary">开启时间锁</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content type2" v-if="type === 1">
|
||||
<img
|
||||
class="desc"
|
||||
src="../../../../assets/img/icon/newicon/left_menu/qingshaonian.png"
|
||||
alt=""
|
||||
/>
|
||||
<div class="content type2" v-if="data.type === 1">
|
||||
<img class="desc" src="@/assets/img/icon/newicon/left_menu/qingshaonian.png" alt="" />
|
||||
<div class="footer">
|
||||
<div class="notice">
|
||||
<span>更多信息可阅读</span>
|
||||
<span
|
||||
style="color: yellow"
|
||||
@click="$nav('/service-protocol', { type: '儿童/青少年使用须知' })"
|
||||
@click="nav('/service-protocol', { type: '儿童/青少年使用须知' })"
|
||||
>《儿童/青少年使用须知》</span
|
||||
>
|
||||
</div>
|
||||
<div class="button primary">开启青少年模式</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content type2" v-if="type === 2">
|
||||
<img class="desc" src="../../../../assets/img/icon/newicon/left_menu/img-type3.png" alt="" />
|
||||
<div class="content type2" v-if="data.type === 2">
|
||||
<img class="desc" src="@/assets/img/icon/newicon/left_menu/img-type3.png" alt="" />
|
||||
<div class="footer">
|
||||
<div class="notice">
|
||||
<!-- TODO 有个勾选没做-->
|
||||
<span>我已阅读并接受</span>
|
||||
<span
|
||||
style="color: yellow"
|
||||
@click="$nav('/service-protocol', { type: '抖音亲子平台服务协议' })"
|
||||
@click="nav('/service-protocol', { type: '抖音亲子平台服务协议' })"
|
||||
>
|
||||
《抖音亲子平台服务协议》
|
||||
</span>
|
||||
</div>
|
||||
<div class="button primary">立即绑定</div>
|
||||
<BaseButton type="primary">立即绑定</BaseButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import enums from '../../../../utils/enums'
|
||||
<script setup lang="ts">
|
||||
import enums from '@/utils/enums'
|
||||
|
||||
export default {
|
||||
name: 'DetailSetting',
|
||||
data() {
|
||||
return {
|
||||
type: 0,
|
||||
enums,
|
||||
triggerTime: enums.TRIGGER_TIME.TIME60
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.type = ~~this.$route.query.type
|
||||
let triggerTime = localStorage.getItem('changeTriggerTime')
|
||||
if (triggerTime !== null) this.triggerTime = triggerTime
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { useRoute } from 'vue-router'
|
||||
import BaseButton from '@/components/BaseButton.vue'
|
||||
|
||||
defineOptions({
|
||||
name: 'DetailSetting'
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
type: 0,
|
||||
triggerTime: enums.TRIGGER_TIME.TIME60
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
data.type = ~~route.query.type
|
||||
let triggerTime = localStorage.getItem('changeTriggerTime')
|
||||
if (triggerTime !== null) data.triggerTime = Number(triggerTime)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -6,21 +6,21 @@
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<div class="row" @click="$nav('detail-setting', { type: 0 })">
|
||||
<div class="row" @click="nav('detail-setting', { type: 0 })">
|
||||
<div class="left">时间锁</div>
|
||||
<div class="right">
|
||||
<span>未开启</span>
|
||||
<dy-back direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('detail-setting', { type: 1 })">
|
||||
<div class="row" @click="nav('detail-setting', { type: 1 })">
|
||||
<div class="left">青少年模式</div>
|
||||
<div class="right">
|
||||
<span>未开启</span>
|
||||
<dy-back direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('detail-setting', { type: 2 })">
|
||||
<div class="row" @click="nav('detail-setting', { type: 2 })">
|
||||
<div class="left">亲子平台</div>
|
||||
<div class="right">
|
||||
<span>未开启</span>
|
||||
@ -30,20 +30,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'index',
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
computed: {},
|
||||
created() {},
|
||||
methods: {}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
|
||||
defineOptions({
|
||||
name: 'MinorProtection'
|
||||
})
|
||||
const nav = useNav()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../../../../assets/less/index';
|
||||
@import '@/assets/less/index';
|
||||
|
||||
.index {
|
||||
position: fixed;
|
||||
|
||||
@ -8,51 +8,53 @@
|
||||
<div class="content">
|
||||
<div class="row" @click="setTriggerTime(enums.TRIGGER_TIME.TIME40)">
|
||||
<div class="left">40分钟</div>
|
||||
<div class="right" v-if="triggerTime === enums.TRIGGER_TIME.TIME40">
|
||||
<div class="right" v-if="data.triggerTime === enums.TRIGGER_TIME.TIME40">
|
||||
<img src="../../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="setTriggerTime(enums.TRIGGER_TIME.TIME60)">
|
||||
<div class="left">60分钟</div>
|
||||
<div class="right" v-if="triggerTime === enums.TRIGGER_TIME.TIME60">
|
||||
<div class="right" v-if="data.triggerTime === enums.TRIGGER_TIME.TIME60">
|
||||
<img src="../../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="setTriggerTime(enums.TRIGGER_TIME.TIME90)">
|
||||
<div class="left">90分钟</div>
|
||||
<div class="right" v-if="triggerTime === enums.TRIGGER_TIME.TIME90">
|
||||
<div class="right" v-if="data.triggerTime === enums.TRIGGER_TIME.TIME90">
|
||||
<img src="../../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="setTriggerTime(enums.TRIGGER_TIME.TIME120)">
|
||||
<div class="left">120分钟</div>
|
||||
<div class="right" v-if="triggerTime === enums.TRIGGER_TIME.TIME120">
|
||||
<div class="right" v-if="data.triggerTime === enums.TRIGGER_TIME.TIME120">
|
||||
<img src="../../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import enums from '../../../../utils/enums'
|
||||
|
||||
export default {
|
||||
name: 'TriggerTime',
|
||||
data() {
|
||||
return {
|
||||
enums,
|
||||
triggerTime: enums.TRIGGER_TIME.TIME60
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.triggerTime = ~~this.$route.query.triggerTime
|
||||
},
|
||||
methods: {
|
||||
setTriggerTime(type) {
|
||||
this.triggerTime = type
|
||||
localStorage.setItem('changeTriggerTime', type)
|
||||
}
|
||||
}
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'ChooseSchool'
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
const data = reactive({
|
||||
triggerTime: enums.TRIGGER_TIME.TIME60
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
data.triggerTime = ~~route.query.triggerTime
|
||||
})
|
||||
|
||||
function setTriggerTime(type) {
|
||||
data.triggerTime = type
|
||||
localStorage.setItem('changeTriggerTime', type)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<div class="title">帐号</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/user.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/user.png" alt="" />
|
||||
<span>帐号与安全</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -18,7 +18,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/lock.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/lock.png" alt="" />
|
||||
<span>隐私设置</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -30,7 +30,7 @@
|
||||
<div class="title">通用</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/remind.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/remind.png" alt="" />
|
||||
<span>通知设置</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -39,7 +39,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/dynamics.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/dynamics.png" alt="" />
|
||||
<span>动态壁纸</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -48,7 +48,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/setting-two.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/setting-two.png" alt="" />
|
||||
<span>通用设置</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -60,7 +60,7 @@
|
||||
<div class="title">帐号互通</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/toutiao.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/toutiao.png" alt="" />
|
||||
<span>头条主页</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -72,7 +72,7 @@
|
||||
<div class="title">关于</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/adddddddd.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/adddddddd.png" alt="" />
|
||||
<span>广告反馈与设置</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -81,7 +81,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/book.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/book.png" alt="" />
|
||||
<span>用户协议</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -90,7 +90,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/bookmark.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/bookmark.png" alt="" />
|
||||
<span>社区自律公约</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -99,7 +99,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/personal-privacy.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/personal-privacy.png" alt="" />
|
||||
<span>隐私政策</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -108,7 +108,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/protect.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/protect.png" alt="" />
|
||||
<span>应用权限</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -117,7 +117,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/ring.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/ring.png" alt="" />
|
||||
<span>第三方SDK列表</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -126,7 +126,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/about.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/about.png" alt="" />
|
||||
<span>关于抖音</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -135,7 +135,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/feedback.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/feedback.png" alt="" />
|
||||
<span>反馈与帮助</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -144,7 +144,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/delete.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/delete.png" alt="" />
|
||||
<span>清理占用空间</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -155,7 +155,7 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/switch.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/switch.png" alt="" />
|
||||
<span>切换空间</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -164,7 +164,7 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="left">
|
||||
<img src="../../../assets/img/icon/newicon/left_menu/logout.png" alt="" />
|
||||
<img src="@/assets/img/icon/newicon/left_menu/logout.png" alt="" />
|
||||
<span>退出登录</span>
|
||||
</div>
|
||||
<div class="right">
|
||||
@ -172,32 +172,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="version">抖音 version{{ version }}</div>
|
||||
<div class="version">抖音 version{{ store.version }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
|
||||
export default {
|
||||
name: 'Setting',
|
||||
setup() {
|
||||
const baseStore = useBaseStore()
|
||||
return { baseStore }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
version: this.baseStore.version
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {},
|
||||
methods: {}
|
||||
}
|
||||
defineOptions({
|
||||
name: 'ChooseSchool'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../../../assets/less/index';
|
||||
@import '@/assets/less/index';
|
||||
|
||||
.Setting {
|
||||
position: fixed;
|
||||
|
||||
@ -11,24 +11,24 @@
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<div class="row" @click="$nav('/me/choose-school')">
|
||||
<div class="row" @click="nav('/me/choose-school')">
|
||||
<div class="left">学校</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(localSchool.name) }}</span>
|
||||
<span>{{ isEmpty(data.localSchool.name) }}</span>
|
||||
<dy-back scale="1" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="checkGo('/me/choose-department')">
|
||||
<div class="left">院系</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(localSchool.department) }}</span>
|
||||
<span>{{ isEmpty(data.localSchool.department) }}</span>
|
||||
<dy-back scale="1" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="showJoinTimeDialog">
|
||||
<div class="left">入学时间</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(localSchool.joinTime) }}</span>
|
||||
<span>{{ isEmpty(data.localSchool.joinTime) }}</span>
|
||||
<dy-back scale="1" direction="right"></dy-back>
|
||||
<div v-show="false" id="trigger1"></div>
|
||||
</div>
|
||||
@ -36,11 +36,14 @@
|
||||
<div class="row" @click="showEducationDialog">
|
||||
<div class="left">学历</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(localSchool.education) }}</span>
|
||||
<span>{{ isEmpty(data.localSchool.education) }}</span>
|
||||
<dy-back scale="1" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('/me/display-type', { displayType: localSchool.displayType })">
|
||||
<div
|
||||
class="row"
|
||||
@click="nav('/me/display-type', { displayType: data.localSchool.displayType })"
|
||||
>
|
||||
<div class="left">展示范围</div>
|
||||
<div class="right">
|
||||
<span>{{ displayType }}</span>
|
||||
@ -51,122 +54,128 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
<script setup lang="ts">
|
||||
import enums from '../../../utils/enums'
|
||||
import { inject } from 'vue'
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import MobileSelect from '../../../components/mobile-select/mobile-select'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import {
|
||||
_hideLoading,
|
||||
_notice,
|
||||
_showLoading,
|
||||
_showSelectDialog,
|
||||
_showSimpleConfirmDialog,
|
||||
_sleep,
|
||||
cloneDeep
|
||||
} from '@/utils'
|
||||
|
||||
//TODO 年份选择器没做
|
||||
export default {
|
||||
name: 'AddSchool',
|
||||
setup() {
|
||||
const baseStore = useBaseStore()
|
||||
return { baseStore }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mitt: inject('mitt'),
|
||||
localSchool: this.$clone(this.baseStore.userinfo.school),
|
||||
educationList: [
|
||||
{ id: 1, name: '专科' },
|
||||
{ id: 2, name: '本科' },
|
||||
{ id: 3, name: '硕士' },
|
||||
{ id: 4, name: '博士' }
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
let school = localStorage.getItem('changeSchool')
|
||||
let department = localStorage.getItem('changeDepartment')
|
||||
let displayType = localStorage.getItem('changeDisplayType')
|
||||
let joinTime = localStorage.getItem('changeJoinTime')
|
||||
let education = localStorage.getItem('changeEducation')
|
||||
if (school !== null) this.localSchool.name = school
|
||||
if (department !== null) this.localSchool.department = department
|
||||
if (displayType !== null) this.localSchool.displayType = ~~displayType
|
||||
if (joinTime !== null) this.localSchool.joinTime = ~~joinTime
|
||||
if (education !== null) this.localSchool.education = education
|
||||
// localStorage.clear()
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['userinfo']),
|
||||
isChanged() {
|
||||
if (this.school.name !== this.localSchool.name) return true
|
||||
if (this.school.department !== this.localSchool.department) return true
|
||||
if (this.school.joinTime !== this.localSchool.joinTime) return true
|
||||
if (this.school.education !== this.localSchool.education) return true
|
||||
return this.school.displayType !== this.localSchool.displayType
|
||||
},
|
||||
displayType() {
|
||||
if (this.localSchool.displayType === enums.DISPLAY_TYPE.ALL) return '公开可见'
|
||||
if (this.localSchool.displayType === enums.DISPLAY_TYPE.SCHOOL) return '校友可见'
|
||||
if (this.localSchool.displayType === enums.DISPLAY_TYPE.ME) return '仅自己可见'
|
||||
return ''
|
||||
},
|
||||
school() {
|
||||
return this.userinfo.school
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showJoinTimeDialog() {
|
||||
new MobileSelect({
|
||||
trigger: '#trigger1',
|
||||
title: '学历',
|
||||
wheels: [
|
||||
{
|
||||
data: Array.apply(null, { length: 50 }).map((v, i) => new Date().getFullYear() - i)
|
||||
}
|
||||
],
|
||||
callback: (indexArr, data) => {
|
||||
localStorage.setItem('changeJoinTime', data[0])
|
||||
this.localSchool.joinTime = ~~data[0]
|
||||
}
|
||||
}).show()
|
||||
},
|
||||
showEducationDialog() {
|
||||
this.$showSelectDialog(this.educationList, (e) => {
|
||||
localStorage.setItem('changeEducation', e.name)
|
||||
this.localSchool.education = e.name
|
||||
})
|
||||
},
|
||||
isEmpty(val) {
|
||||
if (val) return val
|
||||
return '点击设置'
|
||||
},
|
||||
checkGo(path) {
|
||||
if (!this.localSchool.name) return this.$notice('请先选择学校 ')
|
||||
this.$nav(path)
|
||||
},
|
||||
back() {
|
||||
if (this.isChanged) {
|
||||
this.$showSimpleConfirmDialog(
|
||||
'学校信息30天内只允许修改一次,是否保存修改',
|
||||
this.save,
|
||||
() => {
|
||||
localStorage.clear()
|
||||
this.$back()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
localStorage.clear()
|
||||
this.$back()
|
||||
|
||||
defineOptions({
|
||||
name: 'AddSchool'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const router = useRouter()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
localSchool: cloneDeep(store.userinfo.school),
|
||||
educationList: [
|
||||
{ id: 1, name: '专科' },
|
||||
{ id: 2, name: '本科' },
|
||||
{ id: 3, name: '硕士' },
|
||||
{ id: 4, name: '博士' }
|
||||
]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
let school = localStorage.getItem('changeSchool')
|
||||
let department = localStorage.getItem('changeDepartment')
|
||||
let displayType = localStorage.getItem('changeDisplayType')
|
||||
let joinTime = localStorage.getItem('changeJoinTime')
|
||||
let education = localStorage.getItem('changeEducation')
|
||||
if (school !== null) data.localSchool.name = school
|
||||
if (department !== null) data.localSchool.department = department
|
||||
if (displayType !== null) data.localSchool.displayType = ~~displayType
|
||||
if (joinTime !== null) data.localSchool.joinTime = ~~joinTime
|
||||
if (education !== null) data.localSchool.education = education
|
||||
})
|
||||
|
||||
const school = computed(() => {
|
||||
return store.userinfo.school
|
||||
})
|
||||
const isChanged = computed(() => {
|
||||
if (school.value.name !== data.localSchool.name) return true
|
||||
if (school.value.department !== data.localSchool.department) return true
|
||||
if (school.value.joinTime !== data.localSchool.joinTime) return true
|
||||
if (school.value.education !== data.localSchool.education) return true
|
||||
return school.value.displayType !== data.localSchool.displayType
|
||||
})
|
||||
|
||||
const displayType = computed(() => {
|
||||
if (data.localSchool.displayType === enums.DISPLAY_TYPE.ALL) return '公开可见'
|
||||
if (data.localSchool.displayType === enums.DISPLAY_TYPE.SCHOOL) return '校友可见'
|
||||
if (data.localSchool.displayType === enums.DISPLAY_TYPE.ME) return '仅自己可见'
|
||||
return ''
|
||||
})
|
||||
|
||||
function showJoinTimeDialog() {
|
||||
new MobileSelect({
|
||||
trigger: '#trigger1',
|
||||
title: '学历',
|
||||
wheels: [
|
||||
{
|
||||
data: Array.apply(null, { length: 50 }).map((v, i) => new Date().getFullYear() - i)
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
if (!this.isChanged) return
|
||||
this.$showLoading()
|
||||
let data = { ...this.userinfo, ...{ school: this.localSchool } }
|
||||
this.baseStore.setUserinfo(data)
|
||||
await this.$sleep(500)
|
||||
this.$hideLoading()
|
||||
localStorage.clear()
|
||||
this.$back()
|
||||
this.$notice('修改成功')
|
||||
],
|
||||
callback: (indexArr, data) => {
|
||||
localStorage.setItem('changeJoinTime', data[0])
|
||||
data.localSchool.joinTime = ~~data[0]
|
||||
}
|
||||
}).show()
|
||||
}
|
||||
|
||||
function showEducationDialog() {
|
||||
_showSelectDialog(data.educationList, (e) => {
|
||||
localStorage.setItem('changeEducation', e.name)
|
||||
data.localSchool.education = e.name
|
||||
})
|
||||
}
|
||||
|
||||
function isEmpty(val) {
|
||||
if (val) return val
|
||||
return '点击设置'
|
||||
}
|
||||
|
||||
function checkGo(path) {
|
||||
if (!data.localSchool.name) return _notice('请先选择学校 ')
|
||||
nav(path)
|
||||
}
|
||||
|
||||
function back() {
|
||||
if (isChanged.value) {
|
||||
_showSimpleConfirmDialog('学校信息30天内只允许修改一次,是否保存修改', save, () => {
|
||||
localStorage.clear()
|
||||
router.back()
|
||||
})
|
||||
} else {
|
||||
localStorage.clear()
|
||||
router.back()
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (!isChanged.value) return
|
||||
_showLoading()
|
||||
store.userinfo = { ...store.userinfo, ...{ school: data.localSchool } }
|
||||
await _sleep(500)
|
||||
_hideLoading()
|
||||
localStorage.clear()
|
||||
router.back()
|
||||
_notice('修改成功')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<div class="schools">
|
||||
<div class="row" @click="save(item)" :key="i" v-for="(item, i) in list">
|
||||
<div class="row" @click="save()" :key="i" v-for="(item, i) in list">
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -15,56 +15,59 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { _hideLoading, _showLoading, _sleep } from '@/utils'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
|
||||
export default {
|
||||
name: 'ChooseProvince',
|
||||
setup() {
|
||||
const baseStore = useBaseStore()
|
||||
return { baseStore }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [
|
||||
'成都',
|
||||
'自贡',
|
||||
'攀枝花',
|
||||
'泸州',
|
||||
'德阳',
|
||||
'绵阳',
|
||||
'广元',
|
||||
'遂宁',
|
||||
'内江',
|
||||
'乐山',
|
||||
'南充',
|
||||
'眉山',
|
||||
'宜宾',
|
||||
'广安',
|
||||
'达州',
|
||||
'雅安',
|
||||
'巴中',
|
||||
'资阳',
|
||||
'阿坝',
|
||||
'甘孜',
|
||||
'凉山'
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['userinfo'])
|
||||
},
|
||||
methods: {
|
||||
async save() {
|
||||
this.$showLoading()
|
||||
let data = { ...this.userinfo, ...{ location: '中国-四川-成都' } }
|
||||
this.baseStore.setUserinfo(data)
|
||||
await this.$sleep(500)
|
||||
this.$hideLoading()
|
||||
history.go(-3)
|
||||
}
|
||||
}
|
||||
defineOptions({
|
||||
name: 'ChooseCity'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const list = ref([
|
||||
'河北',
|
||||
'山西',
|
||||
'辽宁',
|
||||
'吉林',
|
||||
'黑龙江',
|
||||
'江苏',
|
||||
'浙江',
|
||||
'安徽',
|
||||
'福建',
|
||||
'江西',
|
||||
'山东',
|
||||
'河南',
|
||||
'湖北',
|
||||
'湖南',
|
||||
'广东',
|
||||
'海南',
|
||||
'四川',
|
||||
'贵州',
|
||||
'云南',
|
||||
'陕西',
|
||||
'甘肃',
|
||||
'青海',
|
||||
'台湾',
|
||||
'内蒙古',
|
||||
'广西',
|
||||
'西藏',
|
||||
'宁夏',
|
||||
'新疆',
|
||||
'北京',
|
||||
'天津',
|
||||
'上海',
|
||||
'重庆',
|
||||
'香港',
|
||||
'澳门'
|
||||
])
|
||||
|
||||
async function save() {
|
||||
_showLoading()
|
||||
store.userinfo = { ...store.userinfo, ...{ location: '中国-四川-成都' } }
|
||||
await _sleep(500)
|
||||
_hideLoading()
|
||||
history.go(-3)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -5,12 +5,17 @@
|
||||
<span class="f16">选择院系</span>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<span class="f14" @click="$nav('/me/declare-school', { type: 2 })">没有找到?</span>
|
||||
<span class="f14" @click="nav('/me/declare-school', { type: 2 })">没有找到?</span>
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<div class="nearby">
|
||||
<div class="item" :key="i" v-for="(item, i) in departments" @click="setDepartment(item)">
|
||||
<div
|
||||
class="item"
|
||||
:key="i"
|
||||
v-for="(item, i) in data.departments"
|
||||
@click="setDepartment(item)"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
@ -18,33 +23,36 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ChooseSchool',
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
departments: [],
|
||||
schoolName: ''
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
this.departments.push('院系' + i)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setDepartment(val) {
|
||||
localStorage.setItem('changeDepartment', val)
|
||||
this.$back()
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'ChooseDepartment'
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
departments: [],
|
||||
schoolName: ''
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
data.departments.push('院系' + i)
|
||||
}
|
||||
})
|
||||
|
||||
function setDepartment(val) {
|
||||
localStorage.setItem('changeDepartment', val)
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../../../assets/less/index';
|
||||
@import '@/assets/less/index';
|
||||
|
||||
.choose-school {
|
||||
position: fixed;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<div class="schools">
|
||||
<div class="row" @click="$nav('/me/choose-city')" :key="i" v-for="(item, i) in list">
|
||||
<div class="row" @click="nav('/me/choose-city')" :key="i" v-for="(item, i) in list">
|
||||
<span>{{ item }}</span>
|
||||
<div class="right">
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
@ -18,50 +18,51 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ChooseProvince',
|
||||
data() {
|
||||
return {
|
||||
list: [
|
||||
'河北',
|
||||
'山西',
|
||||
'辽宁',
|
||||
'吉林',
|
||||
'黑龙江',
|
||||
'江苏',
|
||||
'浙江',
|
||||
'安徽',
|
||||
'福建',
|
||||
'江西',
|
||||
'山东',
|
||||
'河南',
|
||||
'湖北',
|
||||
'湖南',
|
||||
'广东',
|
||||
'海南',
|
||||
'四川',
|
||||
'贵州',
|
||||
'云南',
|
||||
'陕西',
|
||||
'甘肃',
|
||||
'青海',
|
||||
'台湾',
|
||||
'内蒙古',
|
||||
'广西',
|
||||
'西藏',
|
||||
'宁夏',
|
||||
'新疆',
|
||||
'北京',
|
||||
'天津',
|
||||
'上海',
|
||||
'重庆',
|
||||
'香港',
|
||||
'澳门'
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
|
||||
defineOptions({
|
||||
name: 'ChooseProvince'
|
||||
})
|
||||
|
||||
const nav = useNav()
|
||||
const list = ref([
|
||||
'河北',
|
||||
'山西',
|
||||
'辽宁',
|
||||
'吉林',
|
||||
'黑龙江',
|
||||
'江苏',
|
||||
'浙江',
|
||||
'安徽',
|
||||
'福建',
|
||||
'江西',
|
||||
'山东',
|
||||
'河南',
|
||||
'湖北',
|
||||
'湖南',
|
||||
'广东',
|
||||
'海南',
|
||||
'四川',
|
||||
'贵州',
|
||||
'云南',
|
||||
'陕西',
|
||||
'甘肃',
|
||||
'青海',
|
||||
'台湾',
|
||||
'内蒙古',
|
||||
'广西',
|
||||
'西藏',
|
||||
'宁夏',
|
||||
'新疆',
|
||||
'北京',
|
||||
'天津',
|
||||
'上海',
|
||||
'重庆',
|
||||
'香港',
|
||||
'澳门'
|
||||
])
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -5,45 +5,50 @@
|
||||
<span class="f16">添加学校</span>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<span class="f14" @click="$nav('/me/declare-school', { type: 1 })">没有找到?</span>
|
||||
<span class="f14" @click="nav('/me/declare-school', { type: 1 })">没有找到?</span>
|
||||
</template>
|
||||
<template v-slot:bottom>
|
||||
<Search
|
||||
class="mt1r mb1r ml2r mr2r"
|
||||
placeholder="搜索大学名称"
|
||||
v-model="schoolName"
|
||||
@clear="isSearch = false"
|
||||
v-model="data.schoolName"
|
||||
@clear="data.isSearch = false"
|
||||
:is-show-right-text="true"
|
||||
@notice="search"
|
||||
></Search>
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<div class="nearby" v-if="!isSearch">
|
||||
<div class="nearby" v-if="!data.isSearch">
|
||||
<div class="title">
|
||||
<img src="../../../assets/img/icon/location.svg" alt="" />
|
||||
<span>离我最近</span>
|
||||
</div>
|
||||
<template v-if="nearby.length">
|
||||
<div class="item" :key="i" v-for="(item, i) in nearby" @click="setSchool(item)">
|
||||
<template v-if="data.nearby.length">
|
||||
<div class="item" :key="i" v-for="(item, i) in data.nearby" @click="setSchool(item)">
|
||||
{{ item }}
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="item">无法获取</div>
|
||||
</div>
|
||||
<div class="line" style="width: calc(100% - 40rem); margin-left: 20rem"></div>
|
||||
<div class="schools" v-if="!isSearch">
|
||||
<div class="item" :key="i" v-for="(item, i) in schools" @click="setSchool(item)">
|
||||
<div class="schools" v-if="!data.isSearch">
|
||||
<div class="item" :key="i" v-for="(item, i) in data.schools" @click="setSchool(item)">
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isSearch">
|
||||
<template v-if="searchSchools.length">
|
||||
<div class="item" :key="i" v-for="(item, i) in searchSchools" @click="setSchool(item)">
|
||||
<span v-if="item.indexOf(schoolName) > -1">
|
||||
{{ item.substr(0, item.indexOf(schoolName)) }}
|
||||
<span style="color: #f50">{{ schoolName }}</span>
|
||||
{{ item.substr(item.indexOf(schoolName) + schoolName.length) }}
|
||||
<div v-if="data.isSearch">
|
||||
<template v-if="data.searchSchools.length">
|
||||
<div
|
||||
class="item"
|
||||
:key="i"
|
||||
v-for="(item, i) in data.searchSchools"
|
||||
@click="setSchool(item)"
|
||||
>
|
||||
<span v-if="item.indexOf(data.schoolName) > -1">
|
||||
{{ item.substr(0, item.indexOf(data.schoolName)) }}
|
||||
<span style="color: #f50">{{ data.schoolName }}</span>
|
||||
{{ item.substr(item.indexOf(data.schoolName) + data.schoolName.length) }}
|
||||
</span>
|
||||
<span v-else>{{ item }}</span>
|
||||
</div>
|
||||
@ -52,48 +57,50 @@
|
||||
<img src="../../../assets/img/icon/head-image.jpeg" alt="" />
|
||||
<div class="title">搜索结果为空</div>
|
||||
<div class="sub-title">没有搜索到相关的内容</div>
|
||||
<div class="btn" @click="$nav('/me/declare-school')">没有学校信息?去申报</div>
|
||||
<div class="btn" @click="nav('/me/declare-school')">没有学校信息?去申报</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Search from '../../../components/Search'
|
||||
<script setup lang="ts">
|
||||
import Search from '../../../components/Search.vue'
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'ChooseSchool',
|
||||
components: {
|
||||
Search
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSearch: false,
|
||||
nearby: [],
|
||||
schools: [],
|
||||
searchSchools: [],
|
||||
schoolName: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
this.nearby.push('附近大学' + i)
|
||||
this.schools.push('所有大学' + i)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setSchool(val) {
|
||||
localStorage.setItem('changeSchool', val)
|
||||
this.$back()
|
||||
},
|
||||
search() {
|
||||
if (!this.schoolName.length) return (this.isSearch = false)
|
||||
this.isSearch = true
|
||||
let all = this.nearby.concat(this.schools)
|
||||
this.searchSchools = all.filter((v) => v.includes(this.schoolName))
|
||||
}
|
||||
defineOptions({
|
||||
name: 'ChooseSchool'
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
isSearch: false,
|
||||
nearby: [],
|
||||
schools: [],
|
||||
searchSchools: [],
|
||||
schoolName: ''
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
for (let i = 0; i < 20; i++) {
|
||||
data.nearby.push('附近大学' + i)
|
||||
data.schools.push('所有大学' + i)
|
||||
}
|
||||
})
|
||||
|
||||
function setSchool(val) {
|
||||
localStorage.setItem('changeSchool', val)
|
||||
router.back()
|
||||
}
|
||||
|
||||
function search() {
|
||||
if (!data.schoolName.length) return (data.isSearch = false)
|
||||
data.isSearch = true
|
||||
let all = data.nearby.concat(data.schools)
|
||||
data.searchSchools = all.filter((v) => v.includes(data.schoolName))
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -8,13 +8,13 @@
|
||||
<div class="content">
|
||||
<div class="row">
|
||||
<div class="label">学校全称</div>
|
||||
<input type="text" placeholder="请输入学校全称(必填)" v-model="form.name" />
|
||||
<input type="text" placeholder="请输入学校全称(必填)" v-model="data.form.name" />
|
||||
</div>
|
||||
<div class="row" v-if="type === 1">
|
||||
<div class="row" v-if="data.type === 1">
|
||||
<div class="label">所在城市</div>
|
||||
<input type="text" placeholder="请输入学校所在城市(必填)" v-model="form.location" />
|
||||
<input type="text" placeholder="请输入学校所在城市(必填)" v-model="data.form.location" />
|
||||
</div>
|
||||
<div class="department-row" v-if="type === 2">
|
||||
<div class="department-row" v-if="data.type === 2">
|
||||
<div class="label">信息问题</div>
|
||||
<div class="right">
|
||||
<span>点击选择(必选)</span>
|
||||
@ -27,32 +27,37 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { _notice } from '@/utils'
|
||||
|
||||
defineOptions({
|
||||
name: 'DeclareSchool'
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const data = reactive({
|
||||
form: {
|
||||
name: '',
|
||||
location: '',
|
||||
departmentInfoType: ''
|
||||
},
|
||||
type: 1
|
||||
})
|
||||
|
||||
//TODO 院系点击那个弹窗没做
|
||||
export default {
|
||||
name: 'DeclareSchool',
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
name: '',
|
||||
location: '',
|
||||
departmentInfoType: ''
|
||||
},
|
||||
type: 1
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.type = Number(this.$route.query.type)
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if (!this.form.name) return this.$notice('请输入学校全称')
|
||||
if (this.type === 1 && !this.form.location) return this.$notice('请输入学校所在城市')
|
||||
if (this.type === 2 && !this.form.departmentInfoType) return this.$notice('请选择信息问题')
|
||||
this.$notice('申报成功')
|
||||
setTimeout(this.$back, 1000)
|
||||
}
|
||||
}
|
||||
onMounted(() => {
|
||||
data.type = Number(route.query.type)
|
||||
})
|
||||
|
||||
function submit() {
|
||||
if (!data.form.name) return _notice('请输入学校全称')
|
||||
if (data.type === 1 && !data.form.location) return _notice('请输入学校所在城市')
|
||||
if (data.type === 2 && !data.form.departmentInfoType) return _notice('请选择信息问题')
|
||||
_notice('申报成功')
|
||||
setTimeout(router.back, 1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -8,46 +8,49 @@
|
||||
<div class="content">
|
||||
<div class="row" @click="setDisplayType(enums.DISPLAY_TYPE.ALL)">
|
||||
<div class="left">公开可见</div>
|
||||
<div class="right" v-if="displayType === enums.DISPLAY_TYPE.ALL">
|
||||
<div class="right" v-if="data.displayType === enums.DISPLAY_TYPE.ALL">
|
||||
<img src="../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="setDisplayType(enums.DISPLAY_TYPE.SCHOOL)">
|
||||
<div class="left">校友可见</div>
|
||||
<div class="right" v-if="displayType === enums.DISPLAY_TYPE.SCHOOL">
|
||||
<div class="right" v-if="data.displayType === enums.DISPLAY_TYPE.SCHOOL">
|
||||
<img src="../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="setDisplayType(enums.DISPLAY_TYPE.ME)">
|
||||
<div class="left">仅自己可见</div>
|
||||
<div class="right" v-if="displayType === enums.DISPLAY_TYPE.ME">
|
||||
<div class="right" v-if="data.displayType === enums.DISPLAY_TYPE.ME">
|
||||
<img src="../../../assets/img/icon/ok-red.png" alt="" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import enums from '../../../utils/enums'
|
||||
|
||||
export default {
|
||||
name: 'DisplayType',
|
||||
data() {
|
||||
return {
|
||||
enums,
|
||||
displayType: enums.DISPLAY_TYPE.ALL
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.displayType = ~~this.$route.query.displayType
|
||||
},
|
||||
methods: {
|
||||
setDisplayType(type) {
|
||||
this.displayType = type
|
||||
localStorage.setItem('changeDisplayType', type)
|
||||
this.$back()
|
||||
}
|
||||
}
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'DisplayType'
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const data = reactive({
|
||||
displayType: enums.DISPLAY_TYPE.ALL
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
data.displayType = ~~route.query.displayType
|
||||
})
|
||||
|
||||
function setDisplayType(type) {
|
||||
data.displayType = type
|
||||
localStorage.setItem('changeDisplayType', type)
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -11,29 +11,29 @@
|
||||
<div class="userinfo">
|
||||
<div class="change-avatar">
|
||||
<div class="avatar-ctn" @click="showAvatarDialog">
|
||||
<img class="avatar" :src="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" />
|
||||
<img class="avatar" :src="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])" alt="" />
|
||||
<img class="change" src="../../../assets/img/icon/me/camera-light.png" alt="" />
|
||||
</div>
|
||||
<span>点击更换头像</span>
|
||||
</div>
|
||||
<div class="row" @click="$nav('/me/edit-userinfo-item', { type: 1 })">
|
||||
<div class="row" @click="nav('/me/edit-userinfo-item', { type: 1 })">
|
||||
<div class="left">名字</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(userinfo.nickname) }}</span>
|
||||
<span>{{ isEmpty(store.userinfo.nickname) }}</span>
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('/me/edit-userinfo-item', { type: 2 })">
|
||||
<div class="row" @click="nav('/me/edit-userinfo-item', { type: 2 })">
|
||||
<div class="left">抖音号</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(_getUserDouyinId({ author: userinfo })) }}</span>
|
||||
<span>{{ isEmpty(_getUserDouyinId({ author: store.userinfo })) }}</span>
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('/me/edit-userinfo-item', { type: 3 })">
|
||||
<div class="row" @click="nav('/me/edit-userinfo-item', { type: 3 })">
|
||||
<div class="left">简介</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(userinfo.signature) }}</span>
|
||||
<span>{{ isEmpty(store.userinfo.signature) }}</span>
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
@ -47,143 +47,143 @@
|
||||
<div class="row" @click="showBirthdayDialog">
|
||||
<div class="left">生日</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(userinfo.user_age) }}</span>
|
||||
<span>{{ isEmpty(store.userinfo.user_age) }}</span>
|
||||
<div v-show="false" id="trigger1"></div>
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('/me/choose-location')">
|
||||
<div class="row" @click="nav('/me/choose-location')">
|
||||
<div class="left">所在地</div>
|
||||
<div class="right">
|
||||
<span v-if="userinfo.province || userinfo.city">
|
||||
{{ userinfo.province }}
|
||||
<template v-if="userinfo.province && userinfo.city"> - </template>
|
||||
{{ userinfo.city }}
|
||||
<span v-if="store.userinfo.province || store.userinfo.city">
|
||||
{{ store.userinfo.province }}
|
||||
<template v-if="store.userinfo.province && store.userinfo.city"> - </template>
|
||||
{{ store.userinfo.city }}
|
||||
</span>
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="$nav('/me/add-school')">
|
||||
<div class="row" @click="nav('/me/add-school')">
|
||||
<div class="left">学校</div>
|
||||
<div class="right">
|
||||
<span>{{ isEmpty(userinfo.school?.name) }}</span>
|
||||
<span>{{ isEmpty(store.userinfo.school?.name) }}</span>
|
||||
<dy-back scale=".8" direction="right"></dy-back>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<transition name="fade">
|
||||
<div class="preview-img" v-if="previewImg" @click="previewImg = ''">
|
||||
<img class="resource" :src="previewImg" alt="" />
|
||||
<div class="preview-img" v-if="data.previewImg" @click="data.previewImg = ''">
|
||||
<img class="resource" :src="data.previewImg" alt="" />
|
||||
<img
|
||||
class="download"
|
||||
src="../../../assets/img/icon/components/video/download.png"
|
||||
alt=""
|
||||
@click.stop="$no"
|
||||
@click.stop="_no"
|
||||
/>
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
import MobileSelect from '../../../components/mobile-select/mobile-select'
|
||||
import { mapState } from 'pinia'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { _checkImgUrl, _getUserDouyinId } from '../../../utils'
|
||||
import {
|
||||
_checkImgUrl,
|
||||
_getUserDouyinId,
|
||||
_hideLoading,
|
||||
_no,
|
||||
_showLoading,
|
||||
_showSelectDialog,
|
||||
_sleep
|
||||
} from '@/utils'
|
||||
import { computed, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
|
||||
export default {
|
||||
name: 'EditUserInfo',
|
||||
setup() {
|
||||
const baseStore = useBaseStore()
|
||||
return { baseStore }
|
||||
},
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
sexList: [
|
||||
{ id: 1, name: '男' },
|
||||
{ id: 2, name: '女' },
|
||||
{ id: 3, name: '不展示' }
|
||||
],
|
||||
avatarList: [
|
||||
{ id: 1, name: '拍一张' },
|
||||
{ id: 2, name: '从相册选择' },
|
||||
{ id: 3, name: '查看大图' },
|
||||
{ id: 4, name: '取消' }
|
||||
],
|
||||
previewImg: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['userinfo']),
|
||||
sex() {
|
||||
switch (this.userinfo.gender) {
|
||||
case 1:
|
||||
return '男'
|
||||
case 2:
|
||||
return '女'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_checkImgUrl,
|
||||
_getUserDouyinId,
|
||||
isEmpty(val) {
|
||||
if (val && val !== -1) return val
|
||||
return '点击设置'
|
||||
},
|
||||
showSexDialog() {
|
||||
this.$showSelectDialog(this.sexList, async (e) => {
|
||||
this.$showLoading()
|
||||
await this.$sleep(500)
|
||||
this.baseStore.setUserinfo({ ...this.userinfo, gender: e.id })
|
||||
this.$hideLoading()
|
||||
})
|
||||
},
|
||||
showAvatarDialog() {
|
||||
this.$showSelectDialog(this.avatarList, (e) => {
|
||||
switch (e.id) {
|
||||
case 1:
|
||||
case 2:
|
||||
return this.$no()
|
||||
case 3:
|
||||
this.previewImg = _checkImgUrl(this.userinfo.cover_url[0].url_list[0])
|
||||
break
|
||||
}
|
||||
})
|
||||
},
|
||||
showBirthdayDialog() {
|
||||
new MobileSelect({
|
||||
trigger: '#trigger1',
|
||||
title: '生日',
|
||||
connector: '生日',
|
||||
wheels: [
|
||||
{
|
||||
data: Array.apply(null, { length: 100 }).map((v, i) => new Date().getFullYear() - i)
|
||||
},
|
||||
{
|
||||
data: Array.apply(null, { length: 12 }).map((v, i) => 12 - i)
|
||||
},
|
||||
{
|
||||
data: Array.apply(null, { length: 31 }).map((v, i) => 31 - i)
|
||||
}
|
||||
],
|
||||
callback: async (indexArr, data) => {
|
||||
console.log(data)
|
||||
this.$showLoading()
|
||||
await this.$sleep(500)
|
||||
this.baseStore.setUserinfo({
|
||||
...this.userinfo,
|
||||
birthday: data.join('-')
|
||||
})
|
||||
this.$hideLoading()
|
||||
// this.localSchool.joinTime = ~~data[0]
|
||||
}
|
||||
}).show()
|
||||
}
|
||||
defineOptions({
|
||||
name: 'EditUserInfo'
|
||||
})
|
||||
const store = useBaseStore()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
sexList: [
|
||||
{ id: 1, name: '男' },
|
||||
{ id: 2, name: '女' },
|
||||
{ id: 3, name: '不展示' }
|
||||
],
|
||||
avatarList: [
|
||||
{ id: 1, name: '拍一张' },
|
||||
{ id: 2, name: '从相册选择' },
|
||||
{ id: 3, name: '查看大图' },
|
||||
{ id: 4, name: '取消' }
|
||||
],
|
||||
previewImg: ''
|
||||
})
|
||||
|
||||
const sex = computed(() => {
|
||||
switch (store.userinfo.gender) {
|
||||
case 1:
|
||||
return '男'
|
||||
case 2:
|
||||
return '女'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
function isEmpty(val) {
|
||||
if (val && val !== -1) return val
|
||||
return '点击设置'
|
||||
}
|
||||
|
||||
function showSexDialog() {
|
||||
_showSelectDialog(data.sexList, async (e) => {
|
||||
_showLoading()
|
||||
await _sleep(500)
|
||||
store.setUserinfo({ ...store.userinfo, gender: e.id })
|
||||
_hideLoading()
|
||||
})
|
||||
}
|
||||
|
||||
function showAvatarDialog() {
|
||||
_showSelectDialog(data.avatarList, (e) => {
|
||||
switch (e.id) {
|
||||
case 1:
|
||||
case 2:
|
||||
return _no()
|
||||
case 3:
|
||||
data.previewImg = _checkImgUrl(store.userinfo.cover_url[0].url_list[0])
|
||||
break
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showBirthdayDialog() {
|
||||
new MobileSelect({
|
||||
trigger: '#trigger1',
|
||||
title: '生日',
|
||||
connector: '生日',
|
||||
wheels: [
|
||||
{
|
||||
data: Array.apply(null, { length: 100 }).map((v, i) => new Date().getFullYear() - i)
|
||||
},
|
||||
{
|
||||
data: Array.apply(null, { length: 12 }).map((v, i) => 12 - i)
|
||||
},
|
||||
{
|
||||
data: Array.apply(null, { length: 31 }).map((v, i) => 31 - i)
|
||||
}
|
||||
],
|
||||
callback: async (indexArr, data) => {
|
||||
_showLoading()
|
||||
await _sleep(500)
|
||||
store.setUserinfo({
|
||||
...store.userinfo,
|
||||
birthday: data.join('-')
|
||||
})
|
||||
_hideLoading()
|
||||
}
|
||||
}).show()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
<div class="edit-item">
|
||||
<BaseHeader @back="back">
|
||||
<template v-slot:center>
|
||||
<span v-if="type === 1" class="f16">修改名字</span>
|
||||
<span v-if="type === 2" class="f16">修改抖音号</span>
|
||||
<span v-if="type === 3" class="f16">修改简介</span>
|
||||
<span v-if="data.type === 1" class="f16">修改名字</span>
|
||||
<span v-if="data.type === 2" class="f16">修改抖音号</span>
|
||||
<span v-if="data.type === 3" class="f16">修改简介</span>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<div>
|
||||
@ -14,37 +14,37 @@
|
||||
</BaseHeader>
|
||||
|
||||
<div class="content">
|
||||
<div v-if="type === 1">
|
||||
<div v-if="data.type === 1">
|
||||
<div class="notice">我的名字</div>
|
||||
<div class="input-ctn" style="margin-bottom: 1rem">
|
||||
<input type="text" v-model="localUserinfo.nickname" placeholder="记得填写名字哦" />
|
||||
<input type="text" v-model="data.localUserinfo.nickname" placeholder="记得填写名字哦" />
|
||||
<img
|
||||
v-if="localUserinfo.nickname"
|
||||
v-if="data.localUserinfo.nickname"
|
||||
style="transform: scale(2)"
|
||||
class="close"
|
||||
src="../../../assets/img/icon/newicon/close-and-bg.png"
|
||||
alt=""
|
||||
@click="localUserinfo.nickname = ''"
|
||||
@click="data.localUserinfo.nickname = ''"
|
||||
/>
|
||||
</div>
|
||||
<div class="num">{{ localUserinfo.nickname.length }}/20</div>
|
||||
<div class="num">{{ data.localUserinfo.nickname.length }}/20</div>
|
||||
</div>
|
||||
<div class="l-row" v-if="type === 2">
|
||||
<div class="l-row" v-if="data.type === 2">
|
||||
<div class="notice">我的抖音号</div>
|
||||
<div class="input-ctn" style="margin-bottom: 10rem">
|
||||
<input type="text" v-model="localUserinfo.unique_id" />
|
||||
<input type="text" v-model="data.localUserinfo.unique_id" />
|
||||
<img
|
||||
v-if="localUserinfo.unique_id"
|
||||
v-if="data.localUserinfo.unique_id"
|
||||
style="transform: scale(2)"
|
||||
class="close"
|
||||
src="../../../assets/img/icon/newicon/close-and-bg.png"
|
||||
alt=""
|
||||
@click="localUserinfo.unique_id = ''"
|
||||
@click="data.localUserinfo.unique_id = ''"
|
||||
/>
|
||||
</div>
|
||||
<div class="num">最多16个字,只允许包含字母、数字、下划线和点,30天内仅能修改一次</div>
|
||||
</div>
|
||||
<div class="l-row" v-if="type === 3">
|
||||
<div class="l-row" v-if="data.type === 3">
|
||||
<div class="notice">个人简介</div>
|
||||
<div class="textarea-ctn">
|
||||
<textarea
|
||||
@ -52,7 +52,7 @@
|
||||
id=""
|
||||
cols="30"
|
||||
rows="10"
|
||||
v-model="localUserinfo.signature"
|
||||
v-model="data.localUserinfo.signature"
|
||||
placeholder="你可以填写兴趣爱好、心情愿望,有趣的介绍能让被关注的概率变高噢!"
|
||||
></textarea>
|
||||
</div>
|
||||
@ -61,60 +61,68 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup lang="ts">
|
||||
//TODO 1、数据变了后,保存按钮变亮;2、数据变了,点返回,弹窗是否确认
|
||||
|
||||
import { mapState } from 'pinia'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { cloneDeep } from '@/utils'
|
||||
import {
|
||||
_hideLoading,
|
||||
_notice,
|
||||
_showLoading,
|
||||
_showSimpleConfirmDialog,
|
||||
_sleep,
|
||||
cloneDeep
|
||||
} from '@/utils'
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
export default {
|
||||
name: 'EditUserInfo',
|
||||
setup() {
|
||||
const baseStore = useBaseStore()
|
||||
return { baseStore }
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
type: 1,
|
||||
localUserinfo: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isChanged() {
|
||||
if (this.type === 1) if (!this.localUserinfo.nickname) return false
|
||||
if (this.type === 2) if (!this.localUserinfo.desc) return false
|
||||
if (this.userinfo.nickname !== this.localUserinfo.nickname) return true
|
||||
if (this.userinfo.desc !== this.localUserinfo.desc) return true
|
||||
return this.userinfo.unique_id !== this.localUserinfo.unique_id
|
||||
},
|
||||
...mapState(useBaseStore, ['userinfo'])
|
||||
},
|
||||
created() {
|
||||
this.localUserinfo = cloneDeep(this.userinfo)
|
||||
this.type = Number(this.$route.query.type)
|
||||
},
|
||||
methods: {
|
||||
back() {
|
||||
if (this.isChanged) {
|
||||
this.$showSimpleConfirmDialog('是否保存修改', this.save, this.$back)
|
||||
} else {
|
||||
this.$back()
|
||||
}
|
||||
},
|
||||
async save() {
|
||||
if (!this.isChanged) return
|
||||
if (this.type === 1) {
|
||||
if (!this.localUserinfo.nickname) return this.$notice('名字不能为空')
|
||||
}
|
||||
this.$showLoading()
|
||||
this.baseStore.setUserinfo(this.localUserinfo)
|
||||
await this.$sleep(500)
|
||||
this.$hideLoading()
|
||||
this.$back()
|
||||
if (this.type === 3) return this.$notice('新签名保存成功')
|
||||
}
|
||||
defineOptions({
|
||||
name: 'EditUserInfo'
|
||||
})
|
||||
const store = useBaseStore()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const data = reactive({
|
||||
type: 1,
|
||||
localUserinfo: {
|
||||
nickname: '',
|
||||
signature: '',
|
||||
unique_id: '',
|
||||
desc: ''
|
||||
}
|
||||
})
|
||||
const isChanged = computed(() => {
|
||||
if (data.type === 1) if (!data.localUserinfo.nickname) return false
|
||||
if (data.type === 2) if (!data.localUserinfo.desc) return false
|
||||
if (store.userinfo.nickname !== data.localUserinfo.nickname) return true
|
||||
if (store.userinfo.desc !== data.localUserinfo.desc) return true
|
||||
return store.userinfo.unique_id !== data.localUserinfo.unique_id
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
data.localUserinfo = cloneDeep(store.userinfo)
|
||||
data.type = Number(route.query.type)
|
||||
})
|
||||
|
||||
function back() {
|
||||
if (isChanged.value) {
|
||||
_showSimpleConfirmDialog('是否保存修改', save, router.back)
|
||||
} else {
|
||||
router.back()
|
||||
}
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (!isChanged.value) return
|
||||
if (data.type === 1) {
|
||||
if (!data.localUserinfo.nickname) return _notice('名字不能为空')
|
||||
}
|
||||
_showLoading()
|
||||
store.setUserinfo(data.localUserinfo)
|
||||
await _sleep(500)
|
||||
_hideLoading()
|
||||
router.back()
|
||||
if (data.type === 3) return _notice('新签名保存成功')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -2,61 +2,65 @@
|
||||
<div id="AllMessage">
|
||||
<BaseHeader>
|
||||
<template v-slot:center>
|
||||
<div class="center" @click="isShowType = !isShowType">
|
||||
<div class="center" @click="data.isShowType = !data.isShowType">
|
||||
<span class="f16">{{ showTypeText }}</span>
|
||||
<img
|
||||
:class="{ show: isShowType }"
|
||||
src="../../assets/img/icon/arrow-up-white.png"
|
||||
:class="{ show: data.isShowType }"
|
||||
src="@/assets/img/icon/arrow-up-white.png"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<transition name="fade">
|
||||
<div class="type-dialog" v-if="isShowType">
|
||||
<div class="type-dialog" v-if="data.isShowType">
|
||||
<div class="dialog-content">
|
||||
<div class="row" @click="toggleShowType(1)">
|
||||
<div class="left">
|
||||
<img src="../../assets/img/icon/message/done-gray.png" alt="" />
|
||||
<img src="@/assets/img/icon/message/done-gray.png" alt="" />
|
||||
<span>全部消息</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="toggleShowType(2)">
|
||||
<div class="left">
|
||||
<img src="../../assets/img/icon/message/like-gray.png" alt="" />
|
||||
<img src="@/assets/img/icon/message/like-gray.png" alt="" />
|
||||
<span>赞</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="toggleShowType(3)">
|
||||
<div class="left">
|
||||
<img src="../../assets/img/icon/message/call-gray.png" alt="" />
|
||||
<img src="@/assets/img/icon/message/call-gray.png" alt="" />
|
||||
<span>@我的</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" @click="toggleShowType(4)">
|
||||
<div class="left">
|
||||
<img src="../../assets/img/icon/message/comment-gray.png" alt="" />
|
||||
<img src="@/assets/img/icon/message/comment-gray.png" alt="" />
|
||||
<span>评论</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mask" @click="isShowType = false"></div>
|
||||
<div class="mask" @click="data.isShowType = false"></div>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="content">
|
||||
<Loading v-if="loading" />
|
||||
<Loading v-if="data.loading" />
|
||||
<Scroll
|
||||
v-else
|
||||
ref="mainScroll"
|
||||
:use-refresh="true"
|
||||
:loading="loadingMore"
|
||||
:loading="data.loadingMore"
|
||||
@refresh="refresh"
|
||||
@pulldown="loadData"
|
||||
>
|
||||
<div class="messages">
|
||||
<div class="message" @click="$nav('/message/visitors')">
|
||||
<div class="message" @click="nav('/message/visitors')">
|
||||
<div class="left">
|
||||
<img v-lazy="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" class="avatar" />
|
||||
<img
|
||||
v-lazy="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])"
|
||||
alt=""
|
||||
class="avatar"
|
||||
/>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="desc">
|
||||
@ -68,27 +72,31 @@
|
||||
<div class="time">01-11</div>
|
||||
</div>
|
||||
</div>
|
||||
<img v-lazy="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" class="poster" />
|
||||
<img
|
||||
v-lazy="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])"
|
||||
alt=""
|
||||
class="poster"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="message" :key="i" v-for="(item, i) in showMessageList" @click="$no">
|
||||
<div class="message" :key="i" v-for="(item, i) in showMessageList" @click="_no">
|
||||
<div class="left">
|
||||
<img v-lazy="$imgPreview(item.author.avatar)" alt="" class="avatar" />
|
||||
<img v-lazy="_checkImgUrl(item.author.avatar)" alt="" class="avatar" />
|
||||
<img
|
||||
v-if="selectShowType === 2"
|
||||
src="../../assets/img/icon/message/love-message.webp"
|
||||
v-if="data.selectShowType === 2"
|
||||
src="@/assets/img/icon/message/love-message.webp"
|
||||
alt=""
|
||||
class="type"
|
||||
/>
|
||||
<img
|
||||
v-if="selectShowType === 3"
|
||||
src="../../assets/img/icon/message/call-message.webp"
|
||||
v-if="data.selectShowType === 3"
|
||||
src="@/assets/img/icon/message/call-message.webp"
|
||||
alt=""
|
||||
class="type"
|
||||
/>
|
||||
<img
|
||||
v-if="selectShowType === 4"
|
||||
src="../../assets/img/icon/message/comment-message.webp"
|
||||
v-if="data.selectShowType === 4"
|
||||
src="@/assets/img/icon/message/comment-message.webp"
|
||||
alt=""
|
||||
class="type"
|
||||
/>
|
||||
@ -100,130 +108,130 @@
|
||||
<div class="tag">朋友</div>
|
||||
</div>
|
||||
<div class="desc-content">
|
||||
<span v-if="selectShowType === 1">好好看啊</span>
|
||||
<span v-if="selectShowType === 2">赞了你的作品</span>
|
||||
<span v-if="selectShowType === 3">@{{ userinfo.nickname }}</span>
|
||||
<span v-if="selectShowType === 4">好好看啊</span>
|
||||
<span v-if="data.selectShowType === 1">好好看啊</span>
|
||||
<span v-if="data.selectShowType === 2">赞了你的作品</span>
|
||||
<span v-if="data.selectShowType === 3">@{{ store.userinfo.nickname }}</span>
|
||||
<span v-if="data.selectShowType === 4">好好看啊</span>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="type" v-if="selectShowType === 3">在评论中提到了你</div>
|
||||
<div class="type" v-if="selectShowType === 4">回复了你的评论</div>
|
||||
<div class="type" v-if="data.selectShowType === 3">在评论中提到了你</div>
|
||||
<div class="type" v-if="data.selectShowType === 4">回复了你的评论</div>
|
||||
<div class="time">01-11</div>
|
||||
</div>
|
||||
</div>
|
||||
<img
|
||||
v-lazy="$imgPreview(item.video + '?vframe/jpg/offset/0/w/300')"
|
||||
v-lazy="_checkImgUrl(item.video + '?vframe/jpg/offset/0/w/300')"
|
||||
alt=""
|
||||
class="poster"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="look-all" v-if="!showAll" @click="showAll = true">
|
||||
<div class="look-all" v-if="!data.showAll" @click="data.showAll = true">
|
||||
<span>查看全部</span>
|
||||
<dy-back />
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">
|
||||
<span>朋友推荐</span>
|
||||
<img src="../../assets/img/icon/about-gray.png" alt="" />
|
||||
<img src="@/assets/img/icon/about-gray.png" alt="" />
|
||||
</div>
|
||||
<Peoples v-model:list="recommend" :loading="loadingMore" mode="recommend" />
|
||||
<Peoples v-model:list="data.recommend" :loading="data.loadingMore" mode="recommend" />
|
||||
</Scroll>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
import Scroll from '../../components/Scroll'
|
||||
import Loading from '../../components/Loading'
|
||||
import Peoples from '../people/components/Peoples'
|
||||
import resource from '../../assets/data/resource.js'
|
||||
import BasePage from '../BasePage'
|
||||
<script setup lang="ts">
|
||||
import Scroll from '@/components/Scroll.vue'
|
||||
import Loading from '@/components/Loading.vue'
|
||||
import Peoples from '../people/components/Peoples.vue'
|
||||
import resource from '@/assets/data/resource.js'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { _checkImgUrl } from '@/utils'
|
||||
import { _checkImgUrl, _no, _notice, _sleep, cloneDeep } from '@/utils'
|
||||
|
||||
export default {
|
||||
extends: BasePage,
|
||||
name: 'AllMessage',
|
||||
components: {
|
||||
Scroll,
|
||||
Loading,
|
||||
Peoples
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
loadingMore: false,
|
||||
isShowType: false,
|
||||
showAll: false,
|
||||
recommend: [],
|
||||
messages: [],
|
||||
selectShowType: 1
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['friends', 'userinfo']),
|
||||
showTypeText() {
|
||||
switch (this.selectShowType) {
|
||||
case 1:
|
||||
return '全部消息'
|
||||
case 2:
|
||||
return '赞'
|
||||
case 3:
|
||||
return '@我的'
|
||||
case 4:
|
||||
return '评论'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
},
|
||||
showMessageList() {
|
||||
if (this.showAll) {
|
||||
return this.messages
|
||||
}
|
||||
return this.messages.slice(0, 2)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
_checkImgUrl,
|
||||
async getData() {
|
||||
this.loading = true
|
||||
await this.$sleep(800)
|
||||
this.loading = false
|
||||
this.recommend = this.$clone(this.friends.all)
|
||||
this.fans = this.$clone(this.friends.all)
|
||||
this.recommend.map((v) => {
|
||||
v.type = -1
|
||||
})
|
||||
this.messages = this.$clone(resource.videos)
|
||||
},
|
||||
toggleShowType(index) {
|
||||
this.selectShowType = index
|
||||
this.isShowType = false
|
||||
},
|
||||
remove(index) {
|
||||
this.$notice('将不会再为你推荐该用户')
|
||||
this.recommend.splice(index, 1)
|
||||
},
|
||||
async refresh() {
|
||||
await this.$sleep(1000)
|
||||
this.$refs.mainScroll.refreshEnd()
|
||||
},
|
||||
async loadData() {
|
||||
if (this.loadingMore) return
|
||||
this.loadingMore = true
|
||||
await this.$sleep(500)
|
||||
this.loadingMore = false
|
||||
let temp = this.$clone(this.friends.all)
|
||||
temp.map((v) => {
|
||||
v.type = -1
|
||||
})
|
||||
this.recommend = this.recommend.concat(temp)
|
||||
}
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
|
||||
defineOptions({
|
||||
name: 'AllMessage'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
loadingMore: false,
|
||||
isShowType: false,
|
||||
showAll: false,
|
||||
recommend: [],
|
||||
fans: [],
|
||||
messages: [],
|
||||
selectShowType: 1
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
const showTypeText = computed(() => {
|
||||
switch (data.selectShowType) {
|
||||
case 1:
|
||||
return '全部消息'
|
||||
case 2:
|
||||
return '赞'
|
||||
case 3:
|
||||
return '@我的'
|
||||
case 4:
|
||||
return '评论'
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
})
|
||||
|
||||
const showMessageList = computed(() => {
|
||||
if (data.showAll) {
|
||||
return data.messages
|
||||
}
|
||||
return data.messages.slice(0, 2)
|
||||
})
|
||||
|
||||
async function getData() {
|
||||
data.loading = true
|
||||
await _sleep(800)
|
||||
data.loading = false
|
||||
data.recommend = cloneDeep(store.friends.all)
|
||||
data.fans = cloneDeep(store.friends.all)
|
||||
data.recommend.map((v) => {
|
||||
v.type = -1
|
||||
})
|
||||
data.messages = cloneDeep(resource.videos)
|
||||
}
|
||||
|
||||
function toggleShowType(index) {
|
||||
data.selectShowType = index
|
||||
data.isShowType = false
|
||||
}
|
||||
|
||||
// function remove(index) {
|
||||
// _notice('将不会再为你推荐该用户')
|
||||
// data.recommend.splice(index, 1)
|
||||
// }
|
||||
|
||||
async function refresh() {
|
||||
await _sleep(1000)
|
||||
//TODO
|
||||
// data.$refs.mainScroll.refreshEnd()
|
||||
}
|
||||
|
||||
async function loadData() {
|
||||
if (data.loadingMore) return
|
||||
data.loadingMore = true
|
||||
await _sleep(500)
|
||||
data.loadingMore = false
|
||||
let temp = cloneDeep(store.friends.all)
|
||||
temp.map((v) => {
|
||||
v.type = -1
|
||||
})
|
||||
data.recommend = data.recommend.concat(temp)
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -6,8 +6,12 @@
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<div>
|
||||
<span class="f16" :class="selectFriends.length ? 'save-yes' : 'save-no'" @click="save">
|
||||
完成{{ selectFriends.length ? `(${selectFriends.length})` : '' }}
|
||||
<span
|
||||
class="f16"
|
||||
:class="data.selectFriends.length ? 'save-yes' : 'save-no'"
|
||||
@click="save"
|
||||
>
|
||||
完成{{ data.selectFriends.length ? `(${data.selectFriends.length})` : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@ -17,11 +21,11 @@
|
||||
<div
|
||||
class="local-row"
|
||||
:key="i"
|
||||
v-for="(item, i) of friends.all"
|
||||
v-for="(item, i) of data.friends.all"
|
||||
@click="toggleSelect(item)"
|
||||
>
|
||||
<Check mode="red" v-model="item.select" />
|
||||
<img :src="$imgPreview(item.avatar)" alt="" />
|
||||
<img :src="_checkImgUrl(item.avatar)" alt="" />
|
||||
<div class="desc">
|
||||
<span class="name">{{
|
||||
item.name.length > 20 ? item.name.substr(0, 20) + '...' : item.name
|
||||
@ -34,62 +38,63 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Check from '../../components/Check'
|
||||
<script setup lang="ts">
|
||||
import Check from '../../components/Check.vue'
|
||||
import { friends } from '@/api/user'
|
||||
|
||||
export default {
|
||||
name: 'Share2Friend',
|
||||
components: { Check },
|
||||
props: {},
|
||||
computed: {
|
||||
// ...mapState(['friends']),
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { _checkImgUrl } from '@/utils'
|
||||
|
||||
defineOptions({
|
||||
name: 'JoinedGroupChat'
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
const data = reactive({
|
||||
friends: {
|
||||
all: {},
|
||||
recent: [],
|
||||
eachOther: []
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
friends: {
|
||||
all: {},
|
||||
recent: [],
|
||||
eachOther: []
|
||||
},
|
||||
selectFriends: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getFriends()
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
if (!this.selectFriends.length) return
|
||||
this.$back()
|
||||
},
|
||||
toggleSelect(item) {
|
||||
let resIndex = this.selectFriends.findIndex((v) => v.name === item.name)
|
||||
if (resIndex !== -1) {
|
||||
item.select = false
|
||||
this.selectFriends.splice(resIndex, 1)
|
||||
} else {
|
||||
item.select = true
|
||||
this.selectFriends.push(item)
|
||||
}
|
||||
},
|
||||
async getFriends() {
|
||||
let res = await friends()
|
||||
if (res.code === this.SUCCESS) {
|
||||
this.friends = res.data
|
||||
this.friends.all = this.friends.all.sort((a, b) => {
|
||||
if (a.pinyin < b.pinyin) return -1
|
||||
if (a.pinyin > b.pinyin) return 1
|
||||
return 0
|
||||
})
|
||||
}
|
||||
}
|
||||
selectFriends: []
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getFriends()
|
||||
})
|
||||
|
||||
function save() {
|
||||
if (!data.selectFriends.length) return
|
||||
router.back()
|
||||
}
|
||||
|
||||
function toggleSelect(item) {
|
||||
let resIndex = data.selectFriends.findIndex((v) => v.name === item.name)
|
||||
if (resIndex !== -1) {
|
||||
item.select = false
|
||||
data.selectFriends.splice(resIndex, 1)
|
||||
} else {
|
||||
item.select = true
|
||||
data.selectFriends.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
async function getFriends() {
|
||||
let res = await friends()
|
||||
if (res.success) {
|
||||
data.friends = res.data
|
||||
data.friends.all = data.friends.all.sort((a, b) => {
|
||||
if (a.pinyin < b.pinyin) return -1
|
||||
if (a.pinyin > b.pinyin) return 1
|
||||
return 0
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@import '../../assets/less/index';
|
||||
@import '@/assets/less/index';
|
||||
|
||||
.Share2Friend {
|
||||
position: fixed;
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<div id="Message" ref="app" :class="createChatDialog ? 'disable-scroll' : ''">
|
||||
<div class="no-search" v-show="!searching">
|
||||
<div id="Message" ref="app" :class="data.createChatDialog ? 'disable-scroll' : ''">
|
||||
<div class="no-search" v-show="!data.searching">
|
||||
<header>
|
||||
<Icon @click="createChatDialog = true" icon="formkit:add" />
|
||||
<Icon @click="data.createChatDialog = true" icon="formkit:add" />
|
||||
<Icon icon="tabler:camera-selfie" />
|
||||
<Icon @click="searching = true" icon="tabler:search" />
|
||||
<Icon @click="data.searching = true" icon="tabler:search" />
|
||||
</header>
|
||||
|
||||
<Scroll ref="mainScroll">
|
||||
<div class="friends pl1r">
|
||||
<div
|
||||
class="friend pr1r pl1r"
|
||||
@click="$nav('/message/chat')"
|
||||
@click="nav('/message/chat')"
|
||||
:key="index"
|
||||
v-for="(item, index) in friends.all"
|
||||
v-for="(item, index) in store.friends.all"
|
||||
>
|
||||
<div class="avatar" :class="index % 2 === 0 ? 'on-line' : ''">
|
||||
<img :src="$imgPreview(item.avatar)" alt="" />
|
||||
<img :src="_checkImgUrl(item.avatar)" alt="" />
|
||||
</div>
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
@ -28,7 +28,7 @@
|
||||
<div class="line mt2r"></div>
|
||||
<div class="messages">
|
||||
<!-- 粉丝-->
|
||||
<div class="message" @click="$nav('/message/fans')">
|
||||
<div class="message" @click="nav('/message/fans')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon1.png" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -45,7 +45,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 互动消息-->
|
||||
<div class="message" @click="$nav('/message/all')">
|
||||
<div class="message" @click="nav('/message/all')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon2.png" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -62,14 +62,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 消息-->
|
||||
<div class="message" @click="$nav('/message/chat')">
|
||||
<div class="message" @click="nav('/message/chat')">
|
||||
<div class="avatar on-line">
|
||||
<img src="../../assets/img/icon/avatar/2.png" alt="" class="head-image" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="left">
|
||||
<div class="name">
|
||||
<span>{{ userinfo.nickname }}</span>
|
||||
<span>{{ store.userinfo.nickname }}</span>
|
||||
</div>
|
||||
<div class="detail">
|
||||
哈哈哈哈哈哈
|
||||
@ -86,7 +86,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 抖音小助手-->
|
||||
<div class="message" @click="$nav('/message/douyin-helper')">
|
||||
<div class="message" @click="nav('/message/douyin-helper')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon5.webp" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -108,7 +108,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 系统通知-->
|
||||
<div class="message" @click="$nav('/message/system-notice')">
|
||||
<div class="message" @click="nav('/message/system-notice')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon4.png" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -130,7 +130,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 求更新-->
|
||||
<div class="message" @click="$nav('/me/request-update')">
|
||||
<div class="message" @click="nav('/me/request-update')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon7.webp" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -152,7 +152,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 任务通知-->
|
||||
<div class="message" @click="$nav('/message/task-notice')">
|
||||
<div class="message" @click="nav('/message/task-notice')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon6.webp" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -174,7 +174,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 直播通知-->
|
||||
<div class="message" @click="$nav('/message/live-notice')">
|
||||
<div class="message" @click="nav('/message/live-notice')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon8.webp" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -196,7 +196,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 钱包通知-->
|
||||
<div class="message" @click="$nav('/message/money-notice')">
|
||||
<div class="message" @click="nav('/message/money-notice')">
|
||||
<div class="avatar">
|
||||
<img src="../../assets/img/icon/msg-icon9.webp" alt="" class="head-image" />
|
||||
</div>
|
||||
@ -246,23 +246,23 @@
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</Scroll>
|
||||
<from-bottom-dialog page-id="Message" v-model="createChatDialog">
|
||||
<div class="create-chat-wrapper" v-show="!showJoinedChat">
|
||||
<from-bottom-dialog page-id="Message" v-model="data.createChatDialog">
|
||||
<div class="create-chat-wrapper" v-show="!data.showJoinedChat">
|
||||
<Search
|
||||
:isShowRightText="isShowRightText"
|
||||
@click="isShowRightText = true"
|
||||
@notice="isShowRightText = false"
|
||||
@clear="isShowRightText = false"
|
||||
:isShowRightText="data.isShowRightText"
|
||||
@click="data.isShowRightText = true"
|
||||
@notice="data.isShowRightText = false"
|
||||
@clear="data.isShowRightText = false"
|
||||
class="ml2r mr2r"
|
||||
placeholder="搜索用户"
|
||||
v-model="createChatSearchKey"
|
||||
v-model="data.createChatSearchKey"
|
||||
></Search>
|
||||
<template v-if="createChatSearchKey">
|
||||
<div class="search-result" v-if="searchFriends.length">
|
||||
<template v-if="data.createChatSearchKey">
|
||||
<div class="search-result" v-if="data.searchFriends.length">
|
||||
<div
|
||||
class="search-result-item"
|
||||
:key="i"
|
||||
v-for="(item, i) in searchFriends"
|
||||
v-for="(item, i) in data.searchFriends"
|
||||
@click="handleClick(item)"
|
||||
>
|
||||
<img class="left" src="../../assets/img/icon/head-image.jpeg" alt="" />
|
||||
@ -286,7 +286,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="joined-chat" @click="showJoinedChat = true">
|
||||
<div class="joined-chat" @click="data.showJoinedChat = true">
|
||||
<img class="left" src="../../assets/img/icon/people-gray.png" alt="" />
|
||||
<div class="right">
|
||||
<span>已加入的群聊</span>
|
||||
@ -298,10 +298,10 @@
|
||||
<div
|
||||
class="friend-item"
|
||||
:key="i"
|
||||
v-for="(item, i) in friends.all"
|
||||
v-for="(item, i) in store.friends.all"
|
||||
@click="item.select = !item.select"
|
||||
>
|
||||
<img class="left" :src="$imgPreview(item.avatar)" alt="" />
|
||||
<img class="left" :src="_checkImgUrl(item.avatar)" alt="" />
|
||||
<div class="right">
|
||||
<span>{{ item.name }}</span>
|
||||
<Check mode="red" style="height: 20rem; width: 20rem" v-model="item.select" />
|
||||
@ -313,9 +313,9 @@
|
||||
<div class="btn" :class="selectFriends ? 'primary' : ''">发起聊天</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="joined-chat-wrapper" v-show="showJoinedChat">
|
||||
<div class="joined-chat-wrapper" v-show="data.showJoinedChat">
|
||||
<div class="nav">
|
||||
<dy-back @click="showJoinedChat = false" mode="light" scale="1.2"></dy-back>
|
||||
<dy-back @click="data.showJoinedChat = false" mode="light" scale="1.2"></dy-back>
|
||||
<span>已加入的群聊</span>
|
||||
<span> </span>
|
||||
</div>
|
||||
@ -326,7 +326,7 @@
|
||||
<div class="right">
|
||||
<div class="title">
|
||||
<div class="name">
|
||||
{{ text.length > 20 ? text.substr(0, 20) + '...' : text }}
|
||||
{{ data.text.length > 20 ? data.text.substr(0, 20) + '...' : data.text }}
|
||||
</div>
|
||||
<div class="num">(3)</div>
|
||||
</div>
|
||||
@ -339,7 +339,7 @@
|
||||
</from-bottom-dialog>
|
||||
|
||||
<transition name="fade">
|
||||
<div class="recommend-dialog" v-if="isShowRecommend">
|
||||
<div class="recommend-dialog" v-if="data.isShowRecommend">
|
||||
<div class="dialog-content">
|
||||
<div class="dialog-header">
|
||||
<img
|
||||
@ -352,15 +352,15 @@
|
||||
<img src="../../assets/img/icon/about-gray.png" alt="" />
|
||||
</div>
|
||||
<img
|
||||
@click="isShowRecommend = false"
|
||||
@click="data.isShowRecommend = false"
|
||||
src="../../assets/img/icon/components/gray-close-full2.png"
|
||||
alt=""
|
||||
/>
|
||||
</div>
|
||||
<div class="dialog-body">
|
||||
<Scroll ref="scroll" @pulldown="loadRecommendData">
|
||||
<Peoples v-model:list="recommend" :loading="loading" mode="recommend" />
|
||||
<Loading :is-full-screen="false" v-if="loading" />
|
||||
<Peoples v-model:list="data.recommend" :loading="data.loading" mode="recommend" />
|
||||
<Loading :is-full-screen="false" v-if="data.loading" />
|
||||
<NoMore v-else />
|
||||
</Scroll>
|
||||
</div>
|
||||
@ -371,22 +371,22 @@
|
||||
<BaseFooter v-bind:init-tab="4" />
|
||||
</div>
|
||||
|
||||
<div class="searching" v-show="searching">
|
||||
<div class="searching" v-show="data.searching">
|
||||
<Search
|
||||
v-model="searchKey"
|
||||
v-model="data.searchKey"
|
||||
right-text="取消"
|
||||
right-text-color="white"
|
||||
@notice="searching = false"
|
||||
@notice="data.searching = false"
|
||||
:isShowRightText="true"
|
||||
/>
|
||||
<div class="more-chat">
|
||||
<template v-if="searchKey">
|
||||
<template v-if="data.searchKey">
|
||||
<div class="sub-title" v-if="searchFriendsAll.length">
|
||||
<span>联系人</span>
|
||||
<div
|
||||
class="right"
|
||||
v-if="searchFriendsAll.length > 3"
|
||||
@click="$nav('/message/more-search', { key: searchKey })"
|
||||
@click="nav('/message/more-search', { key: data.searchKey })"
|
||||
>
|
||||
<span>更多联系人</span>
|
||||
<dy-back mode="gray" img="back" scale=".6" direction="right" />
|
||||
@ -396,15 +396,15 @@
|
||||
v-for="item in searchFriendsAll.slice(0, 3)"
|
||||
:key="item.id"
|
||||
mode="search"
|
||||
:searchKey="searchKey"
|
||||
:searchKey="data.searchKey"
|
||||
:people="item"
|
||||
/>
|
||||
<div class="goto-search-page" @click="$nav('/home/search', { key: searchKey })">
|
||||
<div class="goto-search-page" @click="nav('/home/search', { key: data.searchKey })">
|
||||
<img class="icon" src="../../assets/img/icon/search-light.png" alt="" />
|
||||
<div class="right">
|
||||
<div class="left">
|
||||
<span
|
||||
>搜索 <span style="color: yellow">{{ searchKey }}</span></span
|
||||
>搜索 <span style="color: yellow">{{ data.searchKey }}</span></span
|
||||
>
|
||||
<span class="second-text-color f12">视频、用户、音乐、话题、地点等</span>
|
||||
</div>
|
||||
@ -414,105 +414,96 @@
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="sub-title">更多聊天</div>
|
||||
<People v-for="item in moreChat" :key="item.id" :people="item" />
|
||||
<People v-for="item in data.moreChat" :key="item.id" :people="item" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Search from '../../components/Search'
|
||||
import FromBottomDialog from '../../components/dialog/FromBottomDialog'
|
||||
import Check from '../../components/Check'
|
||||
import { mapState } from 'pinia'
|
||||
import Peoples from '../people/components/Peoples'
|
||||
import Scroll from '../../components/Scroll'
|
||||
import People from '../people/components/People'
|
||||
import BasePage from '../BasePage'
|
||||
<script setup lang="ts">
|
||||
import Search from '../../components/Search.vue'
|
||||
import FromBottomDialog from '../../components/dialog/FromBottomDialog.vue'
|
||||
import Check from '../../components/Check.vue'
|
||||
import Peoples from '../people/components/Peoples.vue'
|
||||
import People from '../people/components/Peoples.vue'
|
||||
import Scroll from '../../components/Scroll.vue'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
|
||||
export default {
|
||||
extends: BasePage,
|
||||
name: 'Message',
|
||||
components: {
|
||||
Scroll,
|
||||
Search,
|
||||
FromBottomDialog,
|
||||
Check,
|
||||
Peoples,
|
||||
People
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isShowRecommend: false,
|
||||
searching: false,
|
||||
searchKey: '',
|
||||
createChatSearchKey: '',
|
||||
showJoinedChat: false,
|
||||
loading: false,
|
||||
createChatDialog: false,
|
||||
isShowRightText: false,
|
||||
text: 'AAAAAAAAA、BBBBBBBBBBBBB、CCCCCCCC',
|
||||
searchFriends: [],
|
||||
recommend: [],
|
||||
moreChat: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['friends', 'userinfo']),
|
||||
selectFriends() {
|
||||
return this.friends.all.filter((v) => v.select).length
|
||||
},
|
||||
searchFriendsAll() {
|
||||
return this.friends.all.filter((v) => {
|
||||
return v.name.search(this.searchKey) !== -1 || v.account.search(this.searchKey) !== -1
|
||||
import { computed, onMounted, reactive, watch } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { _checkImgUrl, _sleep, cloneDeep } from '@/utils'
|
||||
|
||||
defineOptions({
|
||||
name: 'Message'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
isShowRecommend: false,
|
||||
searching: false,
|
||||
searchKey: '',
|
||||
createChatSearchKey: '',
|
||||
showJoinedChat: false,
|
||||
loading: false,
|
||||
createChatDialog: false,
|
||||
isShowRightText: false,
|
||||
text: 'AAAAAAAAA、BBBBBBBBBBBBB、CCCCCCCC',
|
||||
searchFriends: [],
|
||||
recommend: [],
|
||||
moreChat: []
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
console.log('create')
|
||||
data.recommend = cloneDeep(store.friends.all)
|
||||
data.recommend.map((v) => {
|
||||
v.type = -2
|
||||
})
|
||||
data.moreChat = cloneDeep(store.friends.all.slice(0, 3))
|
||||
})
|
||||
|
||||
const selectFriends = computed(() => {
|
||||
return store.friends.all.filter((v) => v.select).length
|
||||
})
|
||||
|
||||
const searchFriendsAll = computed(() => {
|
||||
return store.friends.all.filter((v) => {
|
||||
return v.name.search(data.searchKey) !== -1 || v.account.search(data.searchKey) !== -1
|
||||
})
|
||||
})
|
||||
|
||||
watch(
|
||||
() => data.createChatSearchKey,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
//TODO 搜索时仅仅判断是否包含了对应字符串,抖音做了拼音判断的
|
||||
data.searchFriends = store.friends.all.filter((v) => {
|
||||
if (v.name.includes(newVal)) return true
|
||||
return v.account.includes(newVal)
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
createChatSearchKey(newVal) {
|
||||
if (newVal) {
|
||||
//TODO 搜索时仅仅判断是否包含了对应字符串,抖音做了拼音判断的
|
||||
this.searchFriends = this.friends.all.filter((v) => {
|
||||
if (v.name.includes(newVal)) return true
|
||||
return v.account.includes(newVal)
|
||||
})
|
||||
} else {
|
||||
this.searchFriends = []
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log('create')
|
||||
this.recommend = this.$clone(this.friends.all)
|
||||
this.recommend.map((v) => {
|
||||
v.type = -2
|
||||
})
|
||||
this.moreChat = this.$clone(this.friends.all.slice(0, 3))
|
||||
},
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
// this.isShowRecommend = true
|
||||
}, 1000)
|
||||
},
|
||||
methods: {
|
||||
handleClick(item) {
|
||||
item.select = !item.select
|
||||
this.createChatSearchKey = ''
|
||||
},
|
||||
async loadRecommendData() {
|
||||
if (this.loading) return
|
||||
this.loading = true
|
||||
await this.$sleep(500)
|
||||
this.loading = false
|
||||
let temp = this.$clone(this.friends.all)
|
||||
temp.map((v) => {
|
||||
v.type = -2
|
||||
})
|
||||
this.recommend = this.recommend.concat(temp)
|
||||
} else {
|
||||
data.searchFriends = []
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function handleClick(item) {
|
||||
item.select = !item.select
|
||||
data.createChatSearchKey = ''
|
||||
}
|
||||
|
||||
async function loadRecommendData() {
|
||||
if (data.loading) return
|
||||
data.loading = true
|
||||
await _sleep(500)
|
||||
data.loading = false
|
||||
let temp = cloneDeep(store.friends.all)
|
||||
temp.map((v) => {
|
||||
v.type = -2
|
||||
})
|
||||
data.recommend = data.recommend.concat(temp)
|
||||
}
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -2,53 +2,50 @@
|
||||
<div id="MoreSearch">
|
||||
<div class="content">
|
||||
<Search
|
||||
v-model="searchKey"
|
||||
v-model="data.searchKey"
|
||||
right-text="取消"
|
||||
right-text-color="white"
|
||||
@notice="$back"
|
||||
@notice="router.back"
|
||||
:isShowRightText="true"
|
||||
/>
|
||||
<People
|
||||
v-for="item in searchFriendsAll"
|
||||
:key="item.id"
|
||||
mode="search"
|
||||
:searchKey="searchKey"
|
||||
:searchKey="data.searchKey"
|
||||
:people="item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import Search from '../../components/Search'
|
||||
import { mapState } from 'pinia'
|
||||
import People from '../people/components/People'
|
||||
<script setup lang="ts">
|
||||
import Search from '@/components/Search.vue'
|
||||
import People from '../people/components/Peoples.vue'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
|
||||
export default {
|
||||
name: 'MoreSearch',
|
||||
components: {
|
||||
Search,
|
||||
People
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchKey: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['friends', 'userinfo']),
|
||||
searchFriendsAll() {
|
||||
return this.friends.all.filter((v) => {
|
||||
return v.name.search(this.searchKey) !== -1 || v.account.search(this.searchKey) !== -1
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {},
|
||||
created() {
|
||||
this.searchKey = this.$route.query.key
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'MoreSearch'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const data = reactive({
|
||||
searchKey: ''
|
||||
})
|
||||
|
||||
const searchFriendsAll = computed(() => {
|
||||
return store.friends.all.filter((v) => {
|
||||
return v.name.search(data.searchKey) !== -1 || v.account.search(data.searchKey) !== -1
|
||||
})
|
||||
})
|
||||
onMounted(() => {
|
||||
data.searchKey = String(route.query.key)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -5,12 +5,12 @@
|
||||
<span class="f16">主页访客</span>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<span class="f14" @click="isShowSetting = !isShowSetting">设置</span>
|
||||
<span class="f14" @click="data.isShowSetting = !data.isShowSetting">设置</span>
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<div class="content">
|
||||
<template v-if="realDisplay">
|
||||
<Peoples v-model:list="recommend" :loading="loading" mode="visitor" />
|
||||
<template v-if="data.realDisplay">
|
||||
<Peoples v-model:list="data.recommend" :loading="false" mode="visitor" />
|
||||
<NoMore />
|
||||
</template>
|
||||
<template v-else>
|
||||
@ -18,7 +18,11 @@
|
||||
<div class="header">
|
||||
<div class="wrapper">
|
||||
<img src="../../assets/img/icon/message/display2.webp" alt="" class="icon1" />
|
||||
<img :src="_checkImgUrl(userinfo.cover_url[0].url_list[0])" alt="" class="icon2" />
|
||||
<img
|
||||
:src="_checkImgUrl(store.userinfo.cover_url[0].url_list[0])"
|
||||
alt=""
|
||||
class="icon2"
|
||||
/>
|
||||
<img src="../../assets/img/icon/message/display1.webp" alt="" class="icon3" />
|
||||
</div>
|
||||
</div>
|
||||
@ -31,7 +35,9 @@
|
||||
|
||||
<div class="buttons">
|
||||
<base-button type="dark" @click="keepClose">保持关闭</base-button>
|
||||
<base-button type="primary" @click="display = realDisplay = true">开启访客</base-button>
|
||||
<base-button type="primary" @click="data.display = data.realDisplay = true"
|
||||
>开启访客</base-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -39,7 +45,7 @@
|
||||
|
||||
<from-bottom-dialog
|
||||
page-id="Visitors"
|
||||
v-model="isShowSetting"
|
||||
v-model="data.isShowSetting"
|
||||
mode="white"
|
||||
mask-mode="dark"
|
||||
height="270rem"
|
||||
@ -51,7 +57,7 @@
|
||||
<img class="icon" src="../../assets/img/icon/message/peoples-black2.png" alt="" />
|
||||
<transition name="remove">
|
||||
<img
|
||||
v-if="!display"
|
||||
v-if="!data.display"
|
||||
class="remove"
|
||||
src="../../assets/img/icon/message/remove.png"
|
||||
alt=""
|
||||
@ -60,7 +66,7 @@
|
||||
</div>
|
||||
<img
|
||||
class="close"
|
||||
@click="isShowSetting = false"
|
||||
@click="data.isShowSetting = false"
|
||||
src="../../assets/img/icon/components/gray-close-full2.png"
|
||||
alt=""
|
||||
/>
|
||||
@ -73,60 +79,54 @@
|
||||
<div class="row">
|
||||
<div class="left">展示主页访客</div>
|
||||
<div class="right">
|
||||
<switches v-model="display" theme="bootstrap" color="success"></switches>
|
||||
<switches v-model="data.display" theme="bootstrap" color="success"></switches>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</from-bottom-dialog>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { mapState } from 'pinia'
|
||||
import Peoples from '../people/components/Peoples'
|
||||
import NoMore from '../../components/NoMore'
|
||||
import FromBottomDialog from '../../components/dialog/FromBottomDialog'
|
||||
import Switches from './components/swtich/switches'
|
||||
import BaseButton from '../../components/BaseButton'
|
||||
<script setup lang="ts">
|
||||
import Peoples from '../people/components/Peoples.vue'
|
||||
import NoMore from '@/components/NoMore.vue'
|
||||
import FromBottomDialog from '@/components/dialog/FromBottomDialog.vue'
|
||||
import Switches from './components/swtich/switches.vue'
|
||||
import BaseButton from '@/components/BaseButton.vue'
|
||||
import { useBaseStore } from '@/store/pinia'
|
||||
import { _checkImgUrl } from '@/utils'
|
||||
import { _checkImgUrl, _notice, cloneDeep } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'visitors',
|
||||
components: {
|
||||
BaseButton,
|
||||
FromBottomDialog,
|
||||
Peoples,
|
||||
NoMore,
|
||||
Switches
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
recommend: [],
|
||||
isShowSetting: false,
|
||||
display: false,
|
||||
realDisplay: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isShowSetting(newVal) {
|
||||
if (!newVal) {
|
||||
this.realDisplay = this.display
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(useBaseStore, ['friends', 'userinfo'])
|
||||
},
|
||||
created() {
|
||||
this.recommend = this.$clone(this.friends.all)
|
||||
},
|
||||
methods: {
|
||||
_checkImgUrl,
|
||||
keepClose() {
|
||||
this.$notice('你将不会再收到相关通知')
|
||||
this.$back()
|
||||
import { onMounted, reactive, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'Visitors'
|
||||
})
|
||||
|
||||
const store = useBaseStore()
|
||||
const router = useRouter()
|
||||
const data = reactive({
|
||||
recommend: [],
|
||||
isShowSetting: false,
|
||||
display: false,
|
||||
realDisplay: false
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
data.recommend = cloneDeep(store.friends.all)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => data.isShowSetting,
|
||||
(newVal) => {
|
||||
if (!newVal) {
|
||||
data.realDisplay = data.display
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
function keepClose() {
|
||||
_notice('你将不会再收到相关通知')
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -184,6 +184,7 @@ export default {
|
||||
background: black;
|
||||
border-radius: 50%;
|
||||
width: 80rem;
|
||||
height: 80rem;
|
||||
}
|
||||
|
||||
.icon3 {
|
||||
|
||||
@ -5,13 +5,13 @@
|
||||
<span class="f16">抖音小助手</span>
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<Loading v-if="loading" />
|
||||
<Loading v-if="data.loading" />
|
||||
<Scroll v-else ref="mainScroll">
|
||||
<div class="content">
|
||||
<NoMore />
|
||||
<div class="list">
|
||||
<!--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="title">
|
||||
{{ item.title }}
|
||||
<div class="ml1r not-read" v-if="!item.read"></div>
|
||||
@ -28,82 +28,78 @@
|
||||
</Scroll>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { nextTick } from 'vue'
|
||||
import Scroll from '../../../components/Scroll'
|
||||
import BasePage from '../../BasePage'
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, reactive } from 'vue'
|
||||
import Scroll from '@/components/Scroll.vue'
|
||||
import { _no, _sleep } from '@/utils'
|
||||
|
||||
export default {
|
||||
extends: BasePage,
|
||||
name: 'DouyinHelper',
|
||||
components: { Scroll },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
list: [
|
||||
{
|
||||
read: false,
|
||||
title: '叮!你有一条《长津湖》观看提醒',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'领跑国庆档,吴京、易烊千玺“京玺”兄弟共赴战场!燃爽炸裂的视觉冲击,义勇前行的坚定信念,尽在长津湖“意志之战”。点击查看详情,戳我优惠看>>'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '国庆打卡美好中国',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'山河千年,风景依旧,一幅幅大美的城市山水画在国庆舞台中徐徐展开。点击[查看详情]在拼音打卡美好中国,领跑不同城市的韵味,最高还能赢10000元旅行红包哦!'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '#今天谁请客呢',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'你还在为朋友吃饭谁请客发愁吗?快邀请朋友一起来参加花式甩单挑战,今日消费,淘特请客!还不快来拍摄互动视频?现金大奖等你来分!'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '#寻找武林第一人',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'《天涯明月刀手游》在线悬赏“武林第一人”。10月10日-10月19日内,参与挑战,生成你的专属卡面,测一测你的武林专属称号吧!天刀手游周年庆也在火热进行中,全民福利等你拿! [本活动与Apple Inc.无关]'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '谁是偷偷爱你的人',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'想知道怎么跟TA们走的更近吗?10月11日-10月16日正好有一个合适的机会,赶紧点击了解详情>>'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '看美好奇妙夜,赢万元红包!',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'今天晚上8点,2021抖音美好奇妙夜直播开启!30多位艺人、100多位创作者齐聚一堂,为你带来全方位的视听盛宴,观看直播更有机会赢万元红包大奖,更多精彩,不容错过!快来直接间看看吧! [本活动与Apple Inc.无关]'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
async getData() {
|
||||
this.loading = true
|
||||
await this.$sleep(700)
|
||||
this.loading = false
|
||||
await nextTick()
|
||||
this.$refs.mainScroll.scrollBottom()
|
||||
defineOptions({
|
||||
name: 'DouyinHelper'
|
||||
})
|
||||
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
list: [
|
||||
{
|
||||
read: false,
|
||||
title: '叮!你有一条《长津湖》观看提醒',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'领跑国庆档,吴京、易烊千玺“京玺”兄弟共赴战场!燃爽炸裂的视觉冲击,义勇前行的坚定信念,尽在长津湖“意志之战”。点击查看详情,戳我优惠看>>'
|
||||
},
|
||||
goDetail(item) {
|
||||
item.read = true
|
||||
this.$no()
|
||||
{
|
||||
read: false,
|
||||
title: '国庆打卡美好中国',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'山河千年,风景依旧,一幅幅大美的城市山水画在国庆舞台中徐徐展开。点击[查看详情]在拼音打卡美好中国,领跑不同城市的韵味,最高还能赢10000元旅行红包哦!'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '#今天谁请客呢',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'你还在为朋友吃饭谁请客发愁吗?快邀请朋友一起来参加花式甩单挑战,今日消费,淘特请客!还不快来拍摄互动视频?现金大奖等你来分!'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '#寻找武林第一人',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'《天涯明月刀手游》在线悬赏“武林第一人”。10月10日-10月19日内,参与挑战,生成你的专属卡面,测一测你的武林专属称号吧!天刀手游周年庆也在火热进行中,全民福利等你拿! [本活动与Apple Inc.无关]'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '谁是偷偷爱你的人',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'想知道怎么跟TA们走的更近吗?10月11日-10月16日正好有一个合适的机会,赶紧点击了解详情>>'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '看美好奇妙夜,赢万元红包!',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'今天晚上8点,2021抖音美好奇妙夜直播开启!30多位艺人、100多位创作者齐聚一堂,为你带来全方位的视听盛宴,观看直播更有机会赢万元红包大奖,更多精彩,不容错过!快来直接间看看吧! [本活动与Apple Inc.无关]'
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
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
|
||||
_no()
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -5,18 +5,18 @@
|
||||
<span class="f16">系统通知</span>
|
||||
</template>
|
||||
<template v-slot:right>
|
||||
<span class="f14" @click="$nav('/message/notice-setting', { type: 'SYSTEM' })"
|
||||
<span class="f14" @click="nav('/message/notice-setting', { type: 'SYSTEM' })"
|
||||
>通知设置</span
|
||||
>
|
||||
</template>
|
||||
</BaseHeader>
|
||||
<Loading v-if="loading" />
|
||||
<Loading v-if="data.loading" />
|
||||
<div class="content" v-else>
|
||||
<Scroll ref="mainScroll">
|
||||
<div class="list">
|
||||
<NoMore />
|
||||
<!--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="title">
|
||||
{{ item.title }}
|
||||
<div class="ml1r not-read" v-if="!item.read"></div>
|
||||
@ -32,30 +32,30 @@
|
||||
</Scroll>
|
||||
|
||||
<!--TODO 子页面未做-->
|
||||
<div class="hover-dialog left" v-if="isShowLeftHover">
|
||||
<div class="hover-dialog left" v-if="data.isShowLeftHover">
|
||||
<div class="arrow"></div>
|
||||
<div class="l-row no-border" @click="$no">登录设备管理</div>
|
||||
<div class="l-row" @click="$no">账号锁定</div>
|
||||
<div class="l-row" @click="$no">账号解锁</div>
|
||||
<div class="l-row no-border" @click="_no">登录设备管理</div>
|
||||
<div class="l-row" @click="_no">账号锁定</div>
|
||||
<div class="l-row" @click="_no">账号解锁</div>
|
||||
</div>
|
||||
|
||||
<div class="hover-dialog right" v-if="isShowRightHover">
|
||||
<div class="hover-dialog right" v-if="data.isShowRightHover">
|
||||
<div class="arrow"></div>
|
||||
<div class="l-row no-border" @click="$no">常见问题</div>
|
||||
<div class="l-row" @click="$no">安全课堂</div>
|
||||
<div class="l-row no-border" @click="_no">常见问题</div>
|
||||
<div class="l-row" @click="_no">安全课堂</div>
|
||||
</div>
|
||||
|
||||
<BaseMask mode="white" v-if="isShowMask" @click="isShowMask = false" />
|
||||
<BaseMask mode="white" v-if="data.isShowMask" @click="data.isShowMask = false" />
|
||||
|
||||
<div class="options">
|
||||
<div class="option" @click="isShowLeftHover = !isShowLeftHover">
|
||||
<div class="option" @click="data.isShowLeftHover = !data.isShowLeftHover">
|
||||
<img src="../../../assets/img/icon/message/menu-thin.png" alt="" />
|
||||
<span>自助工具</span>
|
||||
</div>
|
||||
<div class="option" @click="$no">
|
||||
<div class="option" @click="_no">
|
||||
<span>规则中心</span>
|
||||
</div>
|
||||
<div class="option" @click="isShowRightHover = !isShowRightHover">
|
||||
<div class="option" @click="data.isShowRightHover = !data.isShowRightHover">
|
||||
<img src="../../../assets/img/icon/message/menu-thin.png" alt="" />
|
||||
<span>更多帮助</span>
|
||||
</div>
|
||||
@ -63,94 +63,102 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { nextTick } from 'vue'
|
||||
import Scroll from '../../../components/Scroll'
|
||||
import BasePage from '../../BasePage'
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, reactive, watch } from 'vue'
|
||||
import Scroll from '@/components/Scroll.vue'
|
||||
import { useNav } from '@/utils/hooks/useNav.js'
|
||||
import { _no, _sleep } from '@/utils'
|
||||
|
||||
export default {
|
||||
extends: BasePage,
|
||||
name: 'SystemNotice',
|
||||
components: { Scroll },
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
isShowMask: false,
|
||||
isShowLeftHover: false,
|
||||
isShowRightHover: false,
|
||||
list: [
|
||||
{
|
||||
read: false,
|
||||
title: '账号登录提醒',
|
||||
detail: 'xxx',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'您的抖音号4533452342于2021-02-09 07:45:23进行了登录操作。如非本人操作,账号可能被盗。建议立即修改密码,或在[设置-账号与安全-登录设备管理]中删除异常设备。参考设备:iPhone X参考地点:上海市'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '账号登录提醒',
|
||||
detail: 'xxx',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'您的抖音号4533452342于2021-02-09 07:45:23进行了登录操作。如非本人操作,账号可能被盗。建议立即修改密码,或在[设置-账号与安全-登录设备管理]中删除异常设备。参考设备:iPhone X参考地点:上海市'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '协议修订通知',
|
||||
detail: '',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'你好,根据业务开展的实际情况,抖音近期更新了《抖音用户服务协议》《抖音隐私政策》及《儿童/青少年使用须知》中的相关内容。你可以在“我”-“设置”页面中,查看更新后的协议全文。'
|
||||
},
|
||||
{
|
||||
read: false,
|
||||
title: '协议修订通知',
|
||||
detail: '',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'你好,根据业务开展的实际情况,抖音近期更新了《抖音用户服务协议》部分条款的表述。你可以在“我”-“设置”页面中,查看更新后的协议全文。'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isShowLeftHover(newVal) {
|
||||
if (newVal) {
|
||||
this.isShowMask = true
|
||||
}
|
||||
defineOptions({
|
||||
name: 'SystemNotice'
|
||||
})
|
||||
|
||||
const nav = useNav()
|
||||
const data = reactive({
|
||||
loading: false,
|
||||
isShowMask: false,
|
||||
isShowLeftHover: false,
|
||||
isShowRightHover: false,
|
||||
list: [
|
||||
{
|
||||
read: false,
|
||||
title: '账号登录提醒',
|
||||
detail: 'xxx',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'您的抖音号4533452342于2021-02-09 07:45:23进行了登录操作。如非本人操作,账号可能被盗。建议立即修改密码,或在[设置-账号与安全-登录设备管理]中删除异常设备。参考设备:iPhone X参考地点:上海市'
|
||||
},
|
||||
isShowRightHover(newVal) {
|
||||
if (newVal) {
|
||||
this.isShowMask = true
|
||||
}
|
||||
{
|
||||
read: false,
|
||||
title: '账号登录提醒',
|
||||
detail: 'xxx',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'您的抖音号4533452342于2021-02-09 07:45:23进行了登录操作。如非本人操作,账号可能被盗。建议立即修改密码,或在[设置-账号与安全-登录设备管理]中删除异常设备。参考设备:iPhone X参考地点:上海市'
|
||||
},
|
||||
isShowMask(newVal) {
|
||||
if (!newVal) {
|
||||
this.isShowLeftHover = false
|
||||
this.isShowRightHover = false
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {},
|
||||
created() {
|
||||
this.getData()
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
async getData() {
|
||||
this.loading = true
|
||||
await this.$sleep(700)
|
||||
this.loading = false
|
||||
await nextTick()
|
||||
this.$refs.mainScroll.scrollBottom()
|
||||
{
|
||||
read: false,
|
||||
title: '协议修订通知',
|
||||
detail: '',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'你好,根据业务开展的实际情况,抖音近期更新了《抖音用户服务协议》《抖音隐私政策》及《儿童/青少年使用须知》中的相关内容。你可以在“我”-“设置”页面中,查看更新后的协议全文。'
|
||||
},
|
||||
goDetail(item) {
|
||||
item.read = true
|
||||
if (item.detail) {
|
||||
this.$no()
|
||||
}
|
||||
{
|
||||
read: false,
|
||||
title: '协议修订通知',
|
||||
detail: '',
|
||||
time: '2021-10-12 12:12',
|
||||
content:
|
||||
'你好,根据业务开展的实际情况,抖音近期更新了《抖音用户服务协议》部分条款的表述。你可以在“我”-“设置”页面中,查看更新后的协议全文。'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getData()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => data.isShowLeftHover,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
data.isShowMask = true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => data.isShowRightHover,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
data.isShowMask = true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => data.isShowMask,
|
||||
(newVal) => {
|
||||
if (!newVal) {
|
||||
data.isShowLeftHover = false
|
||||
data.isShowRightHover = false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
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>
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="goods-detail base-page" ref="page" @scroll="scroll">
|
||||
<header ref="header">
|
||||
<div class="top">
|
||||
<Icon @click="$back()" icon="material-symbols-light:arrow-back-ios-new" />
|
||||
<Icon @click="router.back()" icon="material-symbols-light:arrow-back-ios-new" />
|
||||
<div class="right">
|
||||
<div class="search">
|
||||
<Icon icon="jam:search" />
|
||||
@ -18,7 +18,7 @@
|
||||
</header>
|
||||
<header class="shadow" ref="headerShadow">
|
||||
<div class="top">
|
||||
<Icon @click="$back()" icon="material-symbols-light:arrow-back-ios-new" />
|
||||
<Icon @click="router.back()" icon="material-symbols-light:arrow-back-ios-new" />
|
||||
<div class="right">
|
||||
<div class="search">
|
||||
<Icon icon="jam:search" />
|
||||
@ -347,7 +347,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import SlideHorizontal from '@/components/slide/SlideHorizontal.vue'
|
||||
import SlideItem from '@/components/slide/SlideItem.vue'
|
||||
import { onMounted, onUnmounted, reactive, ref } from 'vue'
|
||||
@ -357,11 +357,13 @@ import { useBaseStore } from '@/store/pinia'
|
||||
import { recommendedShop } from '@/api/user'
|
||||
import WaterfallList from '@/components/WaterfallList.vue'
|
||||
import ScrollList from '@/components/ScrollList.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
defineOptions({
|
||||
name: 'GoodsDetail'
|
||||
})
|
||||
|
||||
const router = useRouter()
|
||||
let activeIndexs = ref([])
|
||||
const nav = useNav()
|
||||
const store = useBaseStore()
|
||||
@ -382,6 +384,10 @@ function scroll() {
|
||||
|
||||
const state = reactive({
|
||||
detail: {
|
||||
price: '',
|
||||
name: '',
|
||||
sold: '',
|
||||
real_price: '',
|
||||
imgs: []
|
||||
},
|
||||
index: 0,
|
||||
|
||||
@ -112,7 +112,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
<script setup lang="tsx">
|
||||
import { useNav } from '@/utils/hooks/useNav'
|
||||
import { $no, _checkImgUrl } from '@/utils'
|
||||
import ScrollList from '@/components/ScrollList.vue'
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<!-- <video ref="videoEl" :src="v1" controls></video>-->
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
|
||||
defineOptions({
|
||||
|
||||
@ -5,30 +5,12 @@
|
||||
<VideoShare v-model="t" page-id="Test" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import BaseButton from '../../components/BaseButton'
|
||||
import VideoShare from '../home/components/VideoShare'
|
||||
<script setup lang="ts">
|
||||
import BaseButton from '../../components/BaseButton.vue'
|
||||
import VideoShare from '../home/components/VideoShare.vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'Test4',
|
||||
components: {
|
||||
BaseButton,
|
||||
VideoShare
|
||||
},
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '@喵嗷污说电影创作的原声'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
t: false
|
||||
}
|
||||
},
|
||||
methods: {},
|
||||
mounted() {}
|
||||
}
|
||||
const t = ref(false)
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
@ -17,7 +17,7 @@ const router = createRouter({
|
||||
router.beforeEach((to, from) => {
|
||||
const baseStore = useBaseStore()
|
||||
//footer下面的5个按钮,对跳不要用动画
|
||||
let noAnimation = ['/', '/home', '/me', '/shop', '/message', '/publish', '/home/live', '/test']
|
||||
const noAnimation = ['/', '/home', '/me', '/shop', '/message', '/publish', '/home/live', '/test']
|
||||
if (noAnimation.indexOf(from.path) !== -1 && noAnimation.indexOf(to.path) !== -1) {
|
||||
return true
|
||||
}
|
||||
@ -28,7 +28,7 @@ router.beforeEach((to, from) => {
|
||||
|
||||
if (toDepth > fromDepth) {
|
||||
if (to.matched && to.matched.length) {
|
||||
let toComponentName = to.matched[0].components.default.name
|
||||
const toComponentName = to.matched[0].components?.default.name
|
||||
// store.commit('updateExcludeRoutes', {type: 'remove', value: toComponentName})
|
||||
baseStore.updateExcludeRoutes({ type: 'remove', value: toComponentName })
|
||||
// console.log('to', toComponentName)
|
||||
@ -37,7 +37,7 @@ router.beforeEach((to, from) => {
|
||||
}
|
||||
} else {
|
||||
if (from.matched && from.matched.length) {
|
||||
let fromComponentName = from.matched[0].components.default.name
|
||||
const fromComponentName = from.matched[0].components?.default.name
|
||||
// store.commit('updateExcludeRoutes', {type: 'add', value: fromComponentName})
|
||||
baseStore.updateExcludeRoutes({ type: 'add', value: fromComponentName })
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
import Home from '../pages/home'
|
||||
import Test from '../pages/test/Test'
|
||||
import Test4 from '../pages/test/Test4'
|
||||
import Home from '../pages/home/index.vue'
|
||||
import Test from '../pages/test/Test.vue'
|
||||
import Test4 from '../pages/test/Test4.vue'
|
||||
import type { RouteRecordRaw } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
const routes: RouteRecordRaw[] = [
|
||||
// {path: '/', redirect: '/attention'},
|
||||
{ path: '/', redirect: '/home' },
|
||||
{ path: '/test', component: Test },
|
||||
@ -18,6 +18,14 @@ export const useBaseStore = defineStore('base', {
|
||||
routeData: null,
|
||||
users: [],
|
||||
userinfo: {
|
||||
nickname: '',
|
||||
desc: '',
|
||||
user_age: '',
|
||||
signature: '',
|
||||
unique_id: '',
|
||||
province: '',
|
||||
city: '',
|
||||
gender: '',
|
||||
school: {
|
||||
name: '',
|
||||
department: null,
|
||||
|
||||
@ -47,7 +47,12 @@ export const SlideItemPlayStatus = {
|
||||
export const DefaultUser = {
|
||||
nickname: '',
|
||||
unique_id: '',
|
||||
certification: '',
|
||||
short_id: '',
|
||||
province: '',
|
||||
city: '',
|
||||
school: {},
|
||||
uid: '',
|
||||
signature: '', //签名
|
||||
mplatform_followers_count: '', //粉丝
|
||||
following_count: '', //关注
|
||||
|
||||
@ -427,6 +427,10 @@ const Utils = {
|
||||
|
||||
export default Utils
|
||||
|
||||
export function _dateFormat(val, type) {
|
||||
return Utils.$dateFormat(val, type)
|
||||
}
|
||||
|
||||
export function $no() {
|
||||
Utils.$no(arguments)
|
||||
}
|
||||
@ -435,8 +439,8 @@ export function $notice(val) {
|
||||
Utils.$notice(val)
|
||||
}
|
||||
|
||||
export function _notice(val) {
|
||||
Utils.$notice(val)
|
||||
export function _time(val) {
|
||||
return Utils.$time(val)
|
||||
}
|
||||
|
||||
export function _checkImgUrl(url) {
|
||||
@ -467,6 +471,9 @@ export function _getUserDouyinId(item) {
|
||||
return item.author.unique_id || item.author.short_id
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} duration
|
||||
*/
|
||||
export function _sleep(duration) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, duration)
|
||||
@ -499,3 +506,176 @@ export function sampleSize(arr, num) {
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
export function _showLoading() {
|
||||
const app = Vue.createApp({
|
||||
render() {
|
||||
return <Loading />
|
||||
}
|
||||
})
|
||||
let parent = document.createElement('div')
|
||||
parent.classList.add(...['dialog-ctn'])
|
||||
document.body.append(parent)
|
||||
app.mount(parent)
|
||||
}
|
||||
|
||||
export function _hideLoading() {
|
||||
let parent = document.querySelector('.dialog-ctn')
|
||||
parent.remove()
|
||||
}
|
||||
|
||||
export function _showSelectDialog(sexList, cb) {
|
||||
let remove = () => {
|
||||
let parent = document.querySelector('.dialog-ctn')
|
||||
parent.classList.replace('fade-in', 'fade-out')
|
||||
setTimeout(() => {
|
||||
parent.remove()
|
||||
}, 300)
|
||||
}
|
||||
let tempCb = (e) => {
|
||||
remove()
|
||||
cb(e)
|
||||
}
|
||||
const app = Vue.createApp({
|
||||
render() {
|
||||
return <SelectDialog onCancel={remove} list={sexList} onOk={tempCb} />
|
||||
}
|
||||
})
|
||||
let parent = document.createElement('div')
|
||||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||||
document.body.append(parent)
|
||||
app.mount(parent)
|
||||
}
|
||||
|
||||
export function _showSimpleConfirmDialog(title, okCb, cancelCb, okText, cancelText) {
|
||||
if (!cancelCb) {
|
||||
cancelCb = () => {}
|
||||
}
|
||||
let remove = () => {
|
||||
let parent = document.querySelector('.dialog-ctn')
|
||||
parent.classList.replace('fade-in', 'fade-out')
|
||||
setTimeout(() => {
|
||||
parent.remove()
|
||||
}, 300)
|
||||
}
|
||||
let tempOkCb = (e) => {
|
||||
remove()
|
||||
okCb(e)
|
||||
}
|
||||
let tempCancelCb = (e) => {
|
||||
remove()
|
||||
cancelCb(e)
|
||||
}
|
||||
const app = Vue.createApp({
|
||||
render() {
|
||||
return (
|
||||
<SimpleConfirmDialog
|
||||
onCancel={tempCancelCb}
|
||||
onDismiss={remove}
|
||||
title={title}
|
||||
okText={okText}
|
||||
cancelText={cancelText}
|
||||
onOk={tempOkCb}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
let parent = document.createElement('div')
|
||||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||||
document.body.append(parent)
|
||||
app.mount(parent)
|
||||
}
|
||||
|
||||
export function _showConfirmDialog(
|
||||
title,
|
||||
subtitle,
|
||||
subtitleColor,
|
||||
okCb,
|
||||
cancelCb,
|
||||
okText,
|
||||
cancelText,
|
||||
cancelTextColor
|
||||
) {
|
||||
let remove = () => {
|
||||
let parent = document.querySelector('.dialog-ctn')
|
||||
parent.classList.replace('fade-in', 'fade-out')
|
||||
setTimeout(() => {
|
||||
parent.remove()
|
||||
}, 300)
|
||||
}
|
||||
let tempOkCb = (e) => {
|
||||
remove()
|
||||
okCb && okCb(e)
|
||||
}
|
||||
let tempCancelCb = (e) => {
|
||||
remove()
|
||||
cancelCb && cancelCb(e)
|
||||
}
|
||||
const app = Vue.createApp({
|
||||
render() {
|
||||
return (
|
||||
<ConfirmDialog
|
||||
onCancel={tempCancelCb}
|
||||
onDismiss={remove}
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
subtitleColor={subtitleColor}
|
||||
cancelTextColor={cancelTextColor}
|
||||
okText={okText}
|
||||
cancelText={cancelText}
|
||||
onOk={tempOkCb}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
let parent = document.createElement('div')
|
||||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||||
document.body.append(parent)
|
||||
app.mount(parent)
|
||||
}
|
||||
|
||||
export function _showNoticeDialog(title, subtitle, subtitleColor, cancelCb, cancelText) {
|
||||
let remove = () => {
|
||||
let parent = document.querySelector('.dialog-ctn')
|
||||
parent.classList.replace('fade-in', 'fade-out')
|
||||
setTimeout(() => {
|
||||
parent.remove()
|
||||
}, 300)
|
||||
}
|
||||
let tempCancelCb = (e) => {
|
||||
remove()
|
||||
cancelCb(e)
|
||||
}
|
||||
const app = Vue.createApp({
|
||||
render() {
|
||||
return (
|
||||
<NoticeDialog
|
||||
onCancel={tempCancelCb}
|
||||
onDismiss={remove}
|
||||
title={title}
|
||||
subtitleColor={subtitleColor}
|
||||
cancelText={cancelText}
|
||||
subtitle={subtitle}
|
||||
/>
|
||||
)
|
||||
}
|
||||
})
|
||||
let parent = document.createElement('div')
|
||||
parent.classList.add(...['dialog-ctn', 'fade-in'])
|
||||
document.body.append(parent)
|
||||
app.mount(parent)
|
||||
}
|
||||
|
||||
export function _notice(val) {
|
||||
let div = document.createElement('div')
|
||||
div.classList.add('global-notice')
|
||||
div.textContent = val
|
||||
document.body.append(div)
|
||||
setTimeout(() => {
|
||||
document.body.removeChild(div)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
export function _no() {
|
||||
this.$notice('未实现')
|
||||
}
|
||||
|
||||
23
tsconfig.app.json
Normal file
23
tsconfig.app.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": [
|
||||
"env.d.ts",
|
||||
"src/**/*",
|
||||
"src/**/*.vue"
|
||||
],
|
||||
"exclude": [
|
||||
"src/**/__tests__/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"strict": false,
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"./src/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
19
tsconfig.node.json
Normal file
19
tsconfig.node.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
||||
@ -1,20 +1,23 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import { defineConfig, PluginOption } from 'vite'
|
||||
import Vue from '@vitejs/plugin-vue'
|
||||
import VueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import { resolve } from 'path'
|
||||
import { visualizer } from 'rollup-plugin-visualizer'
|
||||
import DefineOptions from 'unplugin-vue-define-options/vite' // 引入插件
|
||||
import { Plugin as importToCDN } from 'vite-plugin-cdn-import'
|
||||
import commonjs from 'vite-plugin-commonjs'
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
|
||||
// import viteImagemin from 'vite-plugin-imagemin'
|
||||
// import viteCompression from 'vite-plugin-compression'
|
||||
|
||||
function pathResolve(dir) {
|
||||
return resolve(__dirname, '.', dir)
|
||||
}
|
||||
|
||||
const lifecycle = process.env.npm_lifecycle_event
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
// {
|
||||
// name: 'axios',
|
||||
// var: 'axios',
|
||||
// path: 'https://lib.baomitu.com/axios/1.6.8/axios.min.js'
|
||||
// },
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
envDir: 'env',
|
||||
@ -29,7 +32,7 @@ export default defineConfig({
|
||||
// // exclude: [/node_modules/, /jQuery\.js/]
|
||||
// // }
|
||||
// }),
|
||||
lifecycle === 'report' ? visualizer({ open: false }) : null,
|
||||
lifecycle === 'report' ? (visualizer({ open: false }) as any as PluginOption) : null,
|
||||
DefineOptions(),
|
||||
Vue(),
|
||||
VueJsx(),
|
||||
@ -55,11 +58,7 @@ export default defineConfig({
|
||||
var: 'Mock',
|
||||
path: 'https://lib.baomitu.com/Mock.js/1.0.1-beta3/mock-min.js'
|
||||
},
|
||||
{
|
||||
name: 'axios',
|
||||
var: 'axios',
|
||||
path: 'https://lib.baomitu.com/axios/1.6.8/axios.min.js'
|
||||
},
|
||||
|
||||
{
|
||||
name: 'jquery',
|
||||
var: '$',
|
||||
@ -109,7 +108,7 @@ export default defineConfig({
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': pathResolve('src')
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
},
|
||||
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
|
||||
},
|
||||
@ -121,7 +120,7 @@ export default defineConfig({
|
||||
manualChunks(id, { getModuleInfo }) {
|
||||
const reg = /(.*)\/src\/components\/(.*)/
|
||||
if (reg.test(id)) {
|
||||
const importersLen = getModuleInfo(id).importers.length
|
||||
const importersLen = getModuleInfo(id)?.importers.length ?? 0
|
||||
// 被多处引用
|
||||
if (importersLen > 1) return 'common'
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user