feat:更新朋友圈功能
This commit is contained in:
@@ -28,7 +28,7 @@
|
||||
<div class="button-info">
|
||||
<el-button type="primary" :icon="Edit" circle :size="'small'"
|
||||
@click="editClick"/>
|
||||
<el-button type="primary" :icon="MoreFilled" circle :size="'small'"
|
||||
<el-button type="primary" :icon="Collection" circle :size="'small'"
|
||||
@click="viewClick()" />
|
||||
<el-button type="danger" :icon="DeleteFilled" circle :size="'small'"
|
||||
@click="deleteClick()" />
|
||||
@@ -59,7 +59,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Edit, MoreFilled, DeleteFilled } from '@element-plus/icons-vue'
|
||||
import { Edit, Collection, DeleteFilled } from '@element-plus/icons-vue'
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { defineProps, onMounted, reactive } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { nextTick, reactive, ref } from 'vue'
|
||||
import { FormRules } from 'element-plus'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { foodMaterialRules } from '@/utils/element/elRules'
|
||||
const rules = reactive<FormRules>(foodMaterialRules)
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<el-dialog v-model="foodStore.stepDialog.visible"
|
||||
:title="foodStore.stepDialog.title"
|
||||
:title="`${foodStore.stepDialog.title}${foodStore.editStepIndex + 1}`"
|
||||
center @open="openDialogEvent"
|
||||
class="food-step-dialog">
|
||||
<el-form ref="formRef" :model="foodStore.stepDialog.data"
|
||||
:rules="rules" label-width="60px">
|
||||
<el-form-item label="内容" prop="content">
|
||||
<el-input v-model="foodStore.stepDialog.data.content" autocomplete="off"
|
||||
placeholder="请输入内容" clearable
|
||||
:placeholder="`请输入步骤${foodStore.editStepIndex + 1}`" clearable
|
||||
type="textarea" :rows="3"
|
||||
show-word-limit maxlength="50">
|
||||
</el-input>
|
||||
@@ -36,7 +36,7 @@
|
||||
import { UploadImage } from 'vue3-common'
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { ref, reactive, nextTick } from 'vue'
|
||||
import { FormRules } from 'element-plus'
|
||||
import type { FormRules } from 'element-plus'
|
||||
import { foodStepRules } from '@/utils/element/elRules'
|
||||
import { fileServiceUrl, serviceFileRootPath } from '@/utils'
|
||||
|
||||
@@ -60,11 +60,13 @@ const openDialogEvent = () => {
|
||||
const confirmClick = () => {
|
||||
formRef.value.validate()
|
||||
.then(async () => {
|
||||
const { editStepIndex: index } = foodStore
|
||||
if (foodStore.stepApiType === 'UPDATE') {
|
||||
const { editStepIndex: index } = foodStore
|
||||
foodStore.currentRecipe.stepList[index] = foodStore.stepDialog.data
|
||||
} else {
|
||||
foodStore.stepDialog.data.sort = foodStore.editStepIndex
|
||||
foodStore.currentRecipe.stepList.push(foodStore.stepDialog.data)
|
||||
foodStore.editStepIndex++
|
||||
}
|
||||
foodStore.stepDialog.visible = false
|
||||
})
|
||||
|
||||
@@ -91,10 +91,14 @@ const userStore = useUserStore()
|
||||
|
||||
const loginFormRef = ref()
|
||||
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
const storageLoginForm = getLocalStorage('loginForm')
|
||||
if (storageLoginForm) {
|
||||
authStore.loginForm = JSON.parse(storageLoginForm)
|
||||
|
||||
if (!authStore.isLogout) {
|
||||
await doLogin('common')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -109,15 +113,7 @@ const handleLogin = async (type: ILoginType) => {
|
||||
authStore.loginLoading = true
|
||||
|
||||
try {
|
||||
await authStore.handleLogin(type)
|
||||
userStore.handleSession(authStore.session)
|
||||
|
||||
// 2. 存储账户密码到localStorage中
|
||||
if (authStore.loginForm.isRemember) {
|
||||
setLocalStorage('loginForm', JSON.stringify(authStore.loginForm))
|
||||
}
|
||||
|
||||
await router.push('/record')
|
||||
await doLogin(type)
|
||||
} finally {
|
||||
authStore.loginLoading = false
|
||||
}
|
||||
@@ -127,4 +123,16 @@ const handleLogin = async (type: ILoginType) => {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const doLogin = async (type: ILoginType) => {
|
||||
await authStore.handleLogin(type)
|
||||
userStore.handleSession(authStore.session)
|
||||
|
||||
// 2. 存储账户密码到localStorage中
|
||||
if (authStore.loginForm.isRemember) {
|
||||
setLocalStorage('loginForm', JSON.stringify(authStore.loginForm))
|
||||
}
|
||||
|
||||
await router.push('/record')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="moment-card card-item">
|
||||
<el-avatar :src="serviceFileRootPath + props.item.avatar" fit="contain"/>
|
||||
<el-avatar :src="avatarUrl" fit="contain" @click="viewProfileClick"/>
|
||||
|
||||
<div class="moment-content">
|
||||
<span class="username">{{ props.item.username }}</span>
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="moment-image-list">
|
||||
<el-image v-for="(item, index) in props.item.imageList" :key="index"
|
||||
:src="serviceFileRootPath + item" fit="cover"
|
||||
:preview-src-list="[serviceFileRootPath + item]"/>
|
||||
:preview-src-list=previewList />
|
||||
</div>
|
||||
|
||||
<p>{{ formatTimeAgo(props.item.date) }}</p>
|
||||
@@ -67,17 +67,19 @@
|
||||
import EmojiPicker from 'vue3-emoji-picker'
|
||||
import 'vue3-emoji-picker/css'
|
||||
import { Edit } from '@element-plus/icons-vue'
|
||||
import { defineProps, reactive } from 'vue'
|
||||
import { computed, defineProps, reactive } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import type { IMoment } from '@/types/food'
|
||||
import { fileServiceUrl, serviceFileRootPath } from '@/utils'
|
||||
import { serviceFileRootPath } from '@/utils'
|
||||
import { formatTimeAgo } from '@/utils/dateUtils'
|
||||
import { useFoodStore } from '@/store/food'
|
||||
import { useUserStore } from '@/store/user'
|
||||
import { useAppStore } from '@/store/app'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const userStore = useUserStore()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const props = defineProps({
|
||||
item: {
|
||||
@@ -93,10 +95,22 @@ const momentInfo = reactive({
|
||||
comment: ''
|
||||
})
|
||||
|
||||
const avatarUrl = computed(() => {
|
||||
if (props.item?.avatar) {
|
||||
return serviceFileRootPath + props.item.avatar
|
||||
} else {
|
||||
return 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
|
||||
}
|
||||
})
|
||||
|
||||
const previewList = computed(() => {
|
||||
return props.item?.imageList.map((item) => serviceFileRootPath + item)
|
||||
})
|
||||
|
||||
const editClick = () => {
|
||||
foodStore.momentApiType = 'UPDATE'
|
||||
foodStore.currentMoment = props.item as IMoment
|
||||
router.push('/moment/momentForm')
|
||||
router.push('/moment/form')
|
||||
}
|
||||
|
||||
const onSelectEmoji = (emoji) => {
|
||||
@@ -109,6 +123,15 @@ const sendCommentClick = async () => {
|
||||
momentInfo.comment = ''
|
||||
momentInfo.isShowComment = false
|
||||
}
|
||||
|
||||
const viewProfileClick = async () => {
|
||||
if (props.item?.userId !== userStore.userInfo.id) {
|
||||
appStore.isShowMobileBack = true
|
||||
foodStore.currentMomentUserId = props.item?.userId as number
|
||||
await userStore.queryUser(foodStore.currentMomentUserId)
|
||||
await router.push('/moment/profile')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
120
src/components/Profile/ProfileCard.vue
Normal file
120
src/components/Profile/ProfileCard.vue
Normal file
@@ -0,0 +1,120 @@
|
||||
<template>
|
||||
<div class="profile-card">
|
||||
<div class="avatar-wrapper">
|
||||
<el-avatar :src="avatarUrl" alt="用户头像" :size="80"
|
||||
fit="contain" @click="previewVisible = true"
|
||||
/>
|
||||
<el-image-viewer
|
||||
v-if="previewVisible"
|
||||
:url-list="[serviceFileRootPath + userStore.userInfo.avatar]"
|
||||
@close="previewVisible = false"
|
||||
/>
|
||||
|
||||
<i v-if="userStore.userInfo.gender"
|
||||
class="fas fa-mars gender-icon" style="color: #409EFF"></i>
|
||||
<i v-else class="fas fa fa-venus gender-icon" style="color: #FFB6C1"></i>
|
||||
</div>
|
||||
|
||||
<span class="user-name">{{ userStore.userInfo.username }}</span>
|
||||
|
||||
<div class="user-info">
|
||||
<div v-if="userStore.userInfo.area" class="info-item">
|
||||
<i class="fas fa-map-marker-alt"></i>
|
||||
<span>{{ userStore.userInfo.area.join('-') }}</span>
|
||||
</div>
|
||||
<div v-if="userStore.userInfo.birthDate" class="info-item">
|
||||
<i class="fas fa-birthday-cake"></i>
|
||||
<span>{{ userStore.userInfo.birthDate }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="userStore.userInfo.job" class="info-item">
|
||||
<i class="fas fa-user-tie"></i>
|
||||
<span>{{ userStore.userInfo.job }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-info">
|
||||
<div v-if="userStore.userInfo.phoneNumber" class="info-item">
|
||||
<i class="fas fa-mobile-alt"></i>
|
||||
<span>{{ userStore.userInfo.phoneNumber }}</span>
|
||||
</div>
|
||||
<div v-if="userStore.userInfo.email" class="info-item">
|
||||
<i class="fas fa-envelope"></i>
|
||||
<span>{{ userStore.userInfo.email }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="userStore.userInfo.tags" class="user-info">
|
||||
<el-tag v-for="(item, index) in userStore.userInfo.tags"
|
||||
:key="index">{{ item }}</el-tag>
|
||||
</div>
|
||||
|
||||
<span v-if="userStore.userInfo.description" class="user-bio">
|
||||
{{ userStore.userInfo.description }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import { useUserStore } from '@/store/user.ts'
|
||||
import { serviceFileRootPath } from '@/utils'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const previewVisible = ref(false)
|
||||
|
||||
const avatarUrl = computed(() => {
|
||||
if (userStore.userInfo.avatar) {
|
||||
return serviceFileRootPath + userStore.userInfo.avatar
|
||||
} else {
|
||||
return 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.profile-card {
|
||||
background: linear-gradient(135deg, #6e8efb, #a777e3);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
.gender-icon {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
bottom: 0;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
padding: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
font-size: 1.1rem;
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user