Bladeren bron

fix(app): 个人主页完善

EvilDragon 4 maanden geleden
bovenliggende
commit
0516f4f835

+ 2 - 2
packages/app/env/.env.development

@@ -5,14 +5,14 @@ VITE_DELETE_CONSOLE = false
 # 是否开启sourcemap
 VITE_SHOW_SOURCEMAP = true
 
-# VITE_SERVER_BASEURL = 'https://www.zhuchaohui.com'
+VITE_SERVER_BASEURL = 'https://www.zhuchaohui.com'
 # VITE_SERVER_BASEURL = 'http://39.106.91.179:48080'
 # VITE_SERVER_BASEURL = 'http://192.168.2.34:48080'
 # 王超
 # VITE_SERVER_BASEURL = 'http://192.168.2.39:48080'
 # VITE_SERVER_BASEURL = 'http://192.168.0.157:48080'
 # 刘岁成
-VITE_SERVER_BASEURL = 'http://192.168.2.38:48080'
+# VITE_SERVER_BASEURL = 'http://192.168.2.38:48080'
 # 赵要军
 # VITE_SERVER_BASEURL = 'http://192.168.2.41:48080'
 # 姚逊涛

+ 40 - 0
packages/app/src/components/upload-evo.vue

@@ -0,0 +1,40 @@
+<script setup lang="ts">
+// defineProps<>()
+const modelValue = defineModel({ type: String, default: '' })
+const props = defineProps<{ multiple?: boolean; limit?: number }>()
+const fileList = ref([])
+const action = ref(`${import.meta.env.VITE_SERVER_BASEURL}/app-api/infra/file/upload`)
+const fileUrls = computed(() => fileList.value.map(({ response }) => JSON.parse(response).data))
+const handleChange = ({ fileList: files }) => {
+  fileList.value = files
+  console.log(fileList.value)
+  console.log(fileUrls.value)
+  if (!props.multiple) {
+    modelValue.value = fileUrls.value[0] || ''
+  }
+}
+watch(
+  () => fileList,
+  () => {
+    console.log(modelValue.value)
+  },
+)
+onMounted(() => {
+  console.log(modelValue.value)
+
+  if (typeof modelValue.value === 'string') {
+    fileList.value = [{ url: modelValue.value }]
+  }
+  console.log(fileList.value)
+})
+</script>
+<template>
+  <wd-upload
+    :file-list="fileList"
+    image-mode="aspectFill"
+    :action="action"
+    :multiple="multiple ?? false"
+    :limit="limit ?? 1"
+    @change="handleChange"
+  ></wd-upload>
+</template>

+ 29 - 1
packages/app/src/core/libs/requests.ts

@@ -665,7 +665,35 @@ export const reserveDesigner = (data: {
 /**
  * 通过ID获取用户信息
  */
-export const getUserInfoById = (id) => httpGet('/app-api/member/user/getByUserId', { id })
+export const getUserInfoById = (id) =>
+  httpGet<
+    Partial<{
+      mobile: string
+      status: string
+      nickname: string
+      avatar: string
+      name: string
+      sex: string
+      areaId: number
+      areaName: string
+      birthday: string
+      mark: string
+      tagIds: string
+      levelId: number
+      groupId: number
+      id: number
+      registerIp: string
+      loginIp: string
+      loginDate: string
+      createTime: string
+      point: number
+      totalPoint: number
+      tagNames: string
+      levelName: string
+      groupName: string
+      experience: number
+    }>
+  >('/app-api/member/user/getByUserId', { id })
 export const refreshToken = (refreshToken: string) =>
   httpPost<any>('/app-api/member/auth/refresh-token', {}, { refreshToken })
 export const httpGetMock = <T>(data: T) =>

+ 130 - 98
packages/app/src/pages/mine/homepage/edit/index.vue

@@ -4,116 +4,148 @@
 <script setup lang="ts">
 import Card from '@/components/card.vue'
 import SectionHeading from '@/components/section-heading.vue'
+import { getDesignerInfo, updateDesignerInfo } from '../../../../core/libs/requests'
+import { useUserStore } from '../../../../store'
+import { storeToRefs } from 'pinia'
+import { pick } from 'radash'
+import { requestToast } from '../../../../core/utils/common'
+import UploadEvo from '@/components/upload-evo.vue'
 
-const action = ref(`${import.meta.env.VITE_SERVER_BASEURL}/app-api/infra/file/upload`)
-
-const tab = ref()
-const tabs = ref([{ label: '商品优惠券' }, { label: '销售积分券' }])
-const data = ref([{}])
-const form = ref({})
-const handleChange = () => {}
-const handleSubmit = () => {
-  console.log(form.value)
+const userStore = useUserStore()
+const { userInfo } = storeToRefs(userStore)
+const form = ref<{
+  userId?: number
+  serviceYears?: number | string
+  homePageUrl?: string
+  sharePageUrl?: string
+  designDesc?: string
+  designFee?: string
+  personalIdentity?: string
+  serviceCustomerCount?: number
+}>()
+const { data, run: setData, loading } = useRequest(() => getDesignerInfo(userInfo.value.userId))
+const handleSubmit = async () => {
+  await requestToast(() => updateDesignerInfo(form.value), {
+    success: true,
+    successTitle: '更新成功',
+  }).then(() => setData())
 }
+onMounted(async () => {
+  await setData()
+  console.log(data.value)
+  form.value = pick(data.value, [
+    'id',
+    'userId',
+    'homePageUrl',
+    'serviceYears',
+    'sharePageUrl',
+    'designDesc',
+    'designFee',
+    'personalIdentity',
+    'serviceCustomerCount',
+  ])
+})
 </script>
 <template>
   <div class="flex-grow flex flex-col gap-6 px-3.5 py-6">
-    <Card>
-      <div>
-        <SectionHeading title="主页封面图"></SectionHeading>
-        <div
-          class="mt-4.5 mb-2.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
-        >
-          用于主页形象封面图,请上传体现个人艺术设计风格的图片,建议竖图尺寸750x1920,也可上传自己的视频介绍
+    <template v-if="form">
+      <Card>
+        <div>
+          <SectionHeading title="主页封面图"></SectionHeading>
+          <div
+            class="mt-4.5 mb-2.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
+          >
+            用于主页形象封面图,请上传体现个人艺术设计风格的图片,建议竖图尺寸750x1920,也可上传自己的视频介绍
+          </div>
+          <UploadEvo v-model="form.homePageUrl"></UploadEvo>
+        </div>
+      </Card>
+      <Card>
+        <div>
+          <SectionHeading title="分享封面图"></SectionHeading>
+          <div
+            class="mt-4.5 mb-2.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
+          >
+            用于分享到微信好友的卡片封面图,尺寸1920x1080;
+          </div>
+          <UploadEvo v-model="form.sharePageUrl"></UploadEvo>
         </div>
-        <wd-upload
-          :file-list="[]"
-          image-mode="aspectFill"
-          :action="action"
-          @change="handleChange"
-        ></wd-upload>
-      </div>
-    </Card>
-    <Card>
-      <div>
-        <SectionHeading title="分享封面图"></SectionHeading>
-        <div
-          class="mt-4.5 mb-2.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
-        >
-          用于分享到微信好友的卡片封面图,尺寸1920x1080;
+      </Card>
+      <SectionHeading title="个人信息"></SectionHeading>
+      <Card>
+        <div>
+          <SectionHeading title="设计理念" subtitle="请输入设计理念"></SectionHeading>
+          <div
+            class="mt-4.5 mx--3.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
+          >
+            <wd-textarea
+              placeholder="例:设计没有风格,设计是对生活的一种诠释,不是所谓的造型与装饰!"
+              v-model="form.designDesc"
+            />
+          </div>
+          <div class="text-end text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug">
+            0/100
+          </div>
         </div>
-        <wd-upload
-          :file-list="[]"
-          image-mode="aspectFill"
-          :action="action"
-          @change="handleChange"
-        ></wd-upload>
-      </div>
-    </Card>
-    <SectionHeading title="个人信息"></SectionHeading>
-    <Card>
-      <div>
-        <SectionHeading title="设计理念" subtitle="请输入设计理念"></SectionHeading>
-        <div
-          class="mt-4.5 mx--3.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
-        >
-          <wd-textarea
-            placeholder="例:设计没有风格,设计是对生活的一种诠释,不是所谓的造型与装饰!"
-          />
+      </Card>
+      <Card>
+        <div>
+          <SectionHeading title="个人信息" subtitle="请输入关于自己身份体现"></SectionHeading>
+          <div
+            class="mt-4.5 mx--3.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
+          >
+            <wd-textarea
+              placeholder="例:中国室内装饰协会会员、 xxx 空间设计事务所创始人、筑巢奖金奖设计师等等"
+              v-model="form.personalIdentity"
+            />
+          </div>
+          <div class="text-end text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug">
+            0/100
+          </div>
         </div>
-        <div class="text-end text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug">
-          0/100
+      </Card>
+      <Card>
+        <div>
+          <SectionHeading title="设计费">
+            <template #append>
+              <div class="flex">
+                <wd-input no-border v-model="form.designFee"></wd-input>
+                <div
+                  class="text-black/40 text-base font-normal font-['PingFang_SC'] leading-relaxed"
+                >
+                  元/㎡
+                </div>
+              </div>
+            </template>
+          </SectionHeading>
         </div>
-      </div>
-    </Card>
-    <Card>
-      <div>
-        <SectionHeading title="个人信息" subtitle="请输入关于自己身份体现"></SectionHeading>
-        <div
-          class="mt-4.5 mx--3.5 text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug"
-        >
-          <wd-textarea
-            placeholder="例:中国室内装饰协会会员、 xxx 空间设计事务所创始人、筑巢奖金奖设计师等等"
-          />
+      </Card>
+      <Card>
+        <div>
+          <SectionHeading title="服务客户数">
+            <template #append>
+              <wd-input
+                placeholder="请输入真实客户数"
+                no-border
+                v-model="form.serviceCustomerCount"
+              ></wd-input>
+            </template>
+          </SectionHeading>
         </div>
-        <div class="text-end text-black/40 text-xs font-normal font-['PingFang_SC'] leading-snug">
-          0/100
+      </Card>
+      <Card>
+        <div>
+          <SectionHeading title="从业年限">
+            <template #append>
+              <wd-input placeholder="请输入年限" no-border v-model="form.serviceYears"></wd-input>
+            </template>
+          </SectionHeading>
         </div>
-      </div>
-    </Card>
-    <Card>
-      <div>
-        <SectionHeading title="设计费">
-          <template #append>
-            <div class="flex">
-              <wd-input no-border></wd-input>
-              <div class="text-black/40 text-base font-normal font-['PingFang_SC'] leading-relaxed">
-                元/㎡
-              </div>
-            </div>
-          </template>
-        </SectionHeading>
-      </div>
-    </Card>
-    <Card>
-      <div>
-        <SectionHeading title="服务客户数">
-          <template #append>
-            <wd-input placeholder="请输入真实客户数" no-border></wd-input>
-          </template>
-        </SectionHeading>
-      </div>
-    </Card>
-    <Card>
-      <div>
-        <SectionHeading title="从业年限">
-          <template #append><wd-input placeholder="请输入年限" no-border></wd-input></template>
-        </SectionHeading>
-      </div>
-    </Card>
-    <!-- <BottomAppBar>
+      </Card>
+      <!-- <BottomAppBar>
       
     </BottomAppBar> -->
-    <div class=""><wd-button block :round="false" @click="handleSubmit">保存</wd-button></div>
+      <div class=""><wd-button block :round="false" @click="handleSubmit">保存</wd-button></div>
+    </template>
   </div>
 </template>

+ 37 - 8
packages/app/src/pages/mine/homepage/index.vue

@@ -7,7 +7,7 @@
 </route>
 <script setup lang="ts">
 import MomentItem from '@/components/moment-item.vue'
-import { getCircles, getDesignerInfo } from '../../../core/libs/requests'
+import { getCircles, getDesignerInfo, getUserInfoById } from '../../../core/libs/requests'
 import { useUserStore } from '../../../store'
 import { storeToRefs } from 'pinia'
 import { NetImages } from '../../../core/libs/net-images'
@@ -21,15 +21,23 @@ const userStore = useUserStore()
 const { userInfo } = storeToRefs(userStore)
 const id = ref()
 const tab = ref('2')
-const circlesData = ref({ list: [] })
 const tabs = ref([
   { label: '案例', value: '2' },
   { label: '动态', value: '1' },
   { label: '视频', value: '0' },
 ])
+const { data: memberInfo, run: setMemberInfo } = useRequest(() => getUserInfoById(id.value), {
+  initialData: {},
+})
 const { data: designerInfo, run: setDesignerInfo } = useRequest(() => getDesignerInfo(id.value), {
   initialData: {},
 })
+const isOwn = computed(() => userInfo.value?.userId === id.value)
+const skills = computed(() => [
+  { label: '从业年限', value: designerInfo.value.serviceYears },
+  { label: '客户', value: designerInfo.value.serviceCustomerCount },
+  { label: '设计费', value: `${designerInfo.value.designFee}元/㎡` },
+])
 onMounted(async () => {})
 function getVideoListByAccessToken(accessToken, openid) {
   const VIDEO_API = 'https://api.weixin.qq.com/wxa/business/getuservideo'
@@ -57,6 +65,7 @@ function getVideoListByAccessToken(accessToken, openid) {
 onLoad(async (query: { id: string }) => {
   if (query.id) {
     id.value = query.id
+    await setMemberInfo()
   } else {
     id.value = userInfo.value.userId
   }
@@ -77,8 +86,8 @@ defineExpose({
     <div class="relative">
       <wd-img
         width="100%"
-        :src="NetImages.DesigerHomepageDefaultBg"
-        mode="widthFix"
+        :src="designerInfo?.homePageUrl || NetImages.DesigerHomepageDefaultBg"
+        mode="aspectFill"
         custom-class="aspect-[1.14/1]"
       />
       <div class="absolute bottom-0 left-0 right-0">
@@ -90,12 +99,12 @@ defineExpose({
               <wd-img
                 width="100%"
                 height="100%"
-                :src="designerInfo?.headImgUrl || userInfo?.avatar"
+                :src="isOwn ? userInfo?.avatar : memberInfo?.avatar"
               ></wd-img>
             </div>
             <div>
               <div class="text-white text-2xl font-normal font-['PingFang_SC'] leading-normal">
-                {{ designerInfo?.brokerName || userInfo?.nickname }}
+                {{ designerInfo?.brokerName }}
               </div>
               <div>
                 <div
@@ -113,14 +122,34 @@ defineExpose({
         </div>
       </div>
     </div>
-    <div class="flex-grow flex flex-col bg-white rounded-t-2xl relative bottom-4">
+    <div class="flex-grow flex flex-col bg-white rounded-t-2xl relative bottom-4 gap-5 px-3.5 pt-5">
+      <div class="flex gap-4">
+        <template v-for="(it, i) in skills" :key="i">
+          <div>
+            <span
+              class="mr-0.575 text-black/90 text-base font-normal font-['PingFang_SC'] leading-[26.98px]"
+            >
+              {{ it.value }}
+            </span>
+            <span
+              class="text-center text-black/40 text-sm font-normal font-['PingFang_SC'] leading-[26.98px]"
+            >
+              {{ it.label }}
+            </span>
+          </div>
+          <div v-if="i < skills?.length - 1" class="leading-[26.98px] text-black/60">|</div>
+        </template>
+      </div>
+      <div class="text-black/80 text-sm font-normal font-['PingFang_SC'] leading-normal">
+        “设计没有风格,设计是对生活的一种诠释,不是所谓的造型与装饰!”
+      </div>
       <wd-tabs v-model="tab" custom-class="bg-transparent!">
         <template v-for="({ label, value }, index) in tabs" :key="index">
           <wd-tab :title="label" :name="value"></wd-tab>
         </template>
       </wd-tabs>
       <PageHelper
-        class="flex-grow flex flex-col bg-[#f6f6f6]"
+        class="flex-grow flex flex-col bg-[#f6f6f6] mx--3.5"
         custom-class=""
         :request="getCircles"
         :query="{ circleType: tab, stylistId: id }"

+ 7 - 4
packages/app/src/pages/publish/moment/index.vue

@@ -1,7 +1,10 @@
-<route lang="yaml">
-style:
-  navigationBarTitleText: 个人动态
-  navigationBarBackgroundColor: '#fff'
+<route lang="json">
+{
+  "style": {
+    "navigationBarTitleText": "个人动态",
+    "navigationBarBackgroundColor": "#fff"
+  }
+}
 </route>
 <script setup lang="ts">
 import SectionHeading from '@/components/section-heading.vue'

+ 16 - 8
packages/app/src/utils/http.ts

@@ -4,12 +4,13 @@ import { useUserStore } from '../store'
 import dayjs from 'dayjs'
 
 const userStore = useUserStore()
-const Authorization = userStore.userInfo.token
-
-const header = {
+console.log(userStore.userInfo)
+const Authorization = userStore.userInfo?.token
+console.log(Authorization)
+const header: { 'tenant-id': number; Authorization?: string } = {
   'tenant-id': 1,
-  Authorization,
 }
+Authorization && (header.Authorization = `Bearer ${Authorization}`)
 export const http = async <T>(options: CustomRequestOptions) => {
   const userStore = useUserStore()
   // console.log(dayjs(userStore.userInfo.expiresTime).format('YYYY-MM-DD HH:mm:ss'))
@@ -41,19 +42,26 @@ export const http = async <T>(options: CustomRequestOptions) => {
       // 响应成功
       success(res) {
         // console.log(res)
-
         // 状态码 2xx,参考 axios 的设计
         if (res.statusCode >= 200 && res.statusCode < 300) {
           // 2.1 提取核心数据 res.data
-          if ((res.data as IResData<T>).code === 401) {
+          if ((res.data as IResData<T>).code === 0) {
+            resolve(res.data as IResData<T>)
+          } else if ((res.data as IResData<T>).code === 401) {
             userStore.clearUserInfo()
+            uni.navigateTo({ url: '/pages/login/index' })
+            reject(res)
           } else {
-            resolve(res.data as IResData<T>)
+            !options.hideErrorToast &&
+              uni.showToast({
+                icon: 'none',
+                title: (res.data as IResData<T>).msg || '请求错误',
+              })
+            reject(res)
           }
         } else if (res.statusCode === 401) {
           // 401错误  -> 清理用户信息,跳转到登录页
           userStore.clearUserInfo()
-          // uni.navigateTo({ url: '/pages/login/login' })
           reject(res)
         } else {
           // 其他错误 -> 根据后端错误信息轻提示