Explorar o código

添加功能: 门店头像上传

shizhongqi hai 1 ano
pai
achega
8e8661e60f
Modificáronse 4 ficheiros con 142 adicións e 6 borrados
  1. 34 0
      .cursor/rules/general-rules.mdc
  2. 2 1
      .gitignore
  3. 98 5
      ghsApp/src/admin/home/me.vue
  4. 8 0
      ghsApp/src/api/shop/index.js

+ 34 - 0
.cursor/rules/general-rules.mdc

@@ -0,0 +1,34 @@
+---
+description: 
+globs: 
+alwaysApply: true
+---
+你是一名顶尖的 uni-app 开发专家,精通 Vue.js (同时支持 Vue 2 和 Vue 3 语法)、JavaScript 和 TypeScript。
+你的首要任务是编写高效、可维护、跨端兼容性强的 uni-app 代码。
+
+### 核心准则
+    1. **API 优先**: 必须优先使用 uni-app 的跨平台 API (例如 `uni.navigateTo`, `uni.request`, `uni.getSystemInfo`),而不是 Web 平台的特有 API (如 `window`, `document`, `localStorage`)。
+    2. **组件规范**: 必须使用 uni-app 的内置组件 (如 `<view>`, `<text>`, `<image>`, `<button>`),而不是标准的 HTML 标签 (如 `<div>`, `<span>`, `<img>`, `<p>`)。
+    3. **生命周期**: 精确理解并使用 uni-app 的页面生命周期 (`onLoad`, `onShow`, `onReady`) 和应用生命周期 (`onLaunch`, `onShow`, `onError`)。
+    4. **条件编译**: 熟练运用条件编译 (`#ifdef H5`, `#ifdef MP-WEIXIN`, `#endif`) 来处理不同平台的特定逻辑和样式。
+    5. **配置文件**: 充分理解 `pages.json` (用于页面路由、导航栏和样式配置) 和 `manifest.json` (用于应用标识、图标、权限和模块配置) 的重要性。
+    6. **样式单位**: 在编写 CSS/SCSS/LESS 时,默认使用 `rpx` 作为响应式尺寸单位,以确保在不同尺寸的设备上表现一致。
+    7. **项目结构**: 认知并遵循标准的 uni-app 项目结构,例如 `pages` 目录存放页面,`components` 存放可复用组件,`static` 存放静态资源, `store` 存放状态管理。
+    8. **性能优化**: 在生成代码时,考虑到小程序的性能限制,例如避免在视图层进行复杂的运算,合理使用 `v-if` 和 `v-show`。
+    9. **Vue 语法**: 如果项目使用 Vue 3,优先使用 Composition API (`<script setup>`) 以获得更好的类型支持和代码组织。如果项目是 Vue 2,则使用 Options API。
+
+
+### 项目结构
+这个目录下放了多个项目,项目分布与说明如下:
+
+- ghs 供货商
+    1. ghsApp   -- 手机微信端(或手机App端界面)
+    2. ghsPad   -- 平板端
+    3. ghs      -- 桌面电脑 web 端
+
+- hd 花店
+    1. hdApp    -- 手机微信端(或手机App端界面)
+    2. hdPad    -- 平板端
+    3. hd       -- 桌面电脑 web 端
+
+注意:各个项目是相互独立的

+ 2 - 1
.gitignore

@@ -1,2 +1,3 @@
 .idea
-.DS_Store
+.DS_Store
+hdApp/dist/release/

+ 98 - 5
ghsApp/src/admin/home/me.vue

@@ -16,8 +16,8 @@
           <view class="me-shop_top">
             <view class="shop-top_left">
 
-              <image :src="myInfo.shopImg" style="width:110upx;border-radius:100upx;" mode="widthFix" v-if="!$util.isEmpty(getLoginInfo.admin) && getLoginInfo.admin.currentGhsShopId > 0"></image>
-              <image :src="myInfo.shopImg" style="width:110upx;border-radius:100upx;" mode="widthFix" @click="pageTo({url:'/admin/home/login'})" v-else></image>
+              <image :src="myInfo.shopImg" class="avatar-img" mode="aspectFill" v-if="!$util.isEmpty(getLoginInfo.admin) && getLoginInfo.admin.currentGhsShopId > 0" @click="openAvatarPopup"></image>
+              <image :src="myInfo.shopImg" class="avatar-img" mode="aspectFill" @click="pageTo({url:'/admin/home/login'})" v-else></image>
 
               <view class="top-info_box" v-if="!$util.isEmpty(getLoginInfo.admin) && getLoginInfo.admin.currentGhsShopId > 0" @click="pageTo({url: '/admin/shop/add?id='+myInfo.shopInfo.id})">
                 <view> {{ myInfo.shopName||'' }}
@@ -212,6 +212,26 @@
 			</view>
 		</uni-popup>
 
+    <uni-popup ref="avatarPopup" type="top" :animation="false">
+      <view class="avatar-popup-content avatar-popup-bg">
+        <image :src="myInfo.shopImg" class="avatar-popup-img" mode="aspectFill"></image>
+        <button class="admin-button-com middle blue avatar-upload-btn" @click="triggerAvatarUpload">上传图片</button>
+      </view>
+      <!-- 隐藏上传组件,只用于触发上传 -->
+      <htz-image-upload
+        ref="avatarUploader"
+        :max="1"
+        :compress="true"
+        v-model="avatarImgData"
+        :headers="headers"
+        :action="getLoginInfo.imgUploadApi"
+        @uploadSuccess="avatarUploadSuccess"
+        :add="false"
+        :remove="false"
+        style="display:none;"
+      ></htz-image-upload>
+    </uni-popup>
+
   </view>
 </template>
 <script>
@@ -225,6 +245,7 @@ import { list } from "@/mixins";
 import { mapGetters } from "vuex";
 import NotLogin from "@/components/not-login";
 import ModalModule from "@/components/plugin/modal"
+import htzImageUpload from '@/components/htz-image-upload/htz-image-upload.vue'
 export default {
   name: "me",
   components: {
@@ -232,7 +253,8 @@ export default {
     TuiListCell,
     ShopSelect,
     NotLogin,
-    ModalModule
+    ModalModule,
+    htzImageUpload
   },
   mixins: [list],
   computed: {
@@ -250,7 +272,9 @@ export default {
       inAmountFocus:false,
       outAmountFocus:false,
       lookMoney:0,
-      showDeadline:false
+      showDeadline:false,
+      avatarImgData: [],
+      headers: { token: '' },
     };
   },
   onPullDownRefresh () {
@@ -282,6 +306,8 @@ export default {
     // #ifdef MP-WEIXIN
     this.showDeadline = true
     // #endif
+    const token = uni.getStorageSync('token')
+    this.headers.token = token
   },
   methods: {
 		closeGzh(){
@@ -477,7 +503,42 @@ export default {
           }
         })
       })
-    }
+    },
+    openAvatarPopup() {
+      this.avatarImgData = []
+      this.$refs.avatarPopup.open('top')
+    },
+    triggerAvatarUpload() {
+      // 直接通过 ref 触发上传
+      this.$refs.avatarUploader && this.$refs.avatarUploader.chooseFile()
+    },
+    async avatarUploadSuccess(res) {
+      // 上传成功后,调用 /shop/update-avatar 更新头像
+      let _res = JSON.parse(res.data)
+      if(_res.code == 1 && _res.data && _res.data.shortUrl) {
+        // shopId 从 myInfo.shopInfo.id 获取
+        const shopId = this.myInfo.shopInfo && this.myInfo.shopInfo.id
+        if(!shopId) {
+          this.$msg('门店信息异常,无法更新头像')
+          return
+        }
+        // 调用 /shop/update-avatar
+        const { updateShopAvatar } = require('@/api/shop')
+        uni.showLoading({mask:true})
+        updateShopAvatar({ shopId: shopId, avatar: _res.data.shortUrl }).then(resp => {
+          uni.hideLoading()
+          if(resp.code == 1) {
+            this.$msg('头像更新成功')
+            this.myInfo.shopImg = resp.data.shopImg
+            this.$refs.avatarPopup.close()
+          } else {
+            this.$msg(resp.msg || '头像更新失败')
+          }
+        })
+      } else {
+        this.$msg('图片上传失败')
+      }
+    },
   },
 };
 </script>
@@ -655,5 +716,37 @@ export default {
     margin-top: 20upx;
     border-radius: 10upx;
   }
+  .avatar-popup-bg {
+    background: #fff;
+    opacity: 1;
+    border-bottom-left-radius: 24upx;
+    border-bottom-right-radius: 24upx;
+  }
+  .avatar-popup-content {
+    min-height: 42vh;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: flex-start;
+    padding: 148upx 0 32upx 0;
+  }
+  .avatar-img {
+    width: 110upx;
+    height: 110upx;
+    border-radius: 50%;
+    object-fit: cover;
+  }
+  .avatar-popup-img {
+    width: 350upx;
+    height: 350upx;
+    border-radius: 50%;
+    object-fit: cover;
+    margin-bottom: 10upx;
+    border: 3upx solid #3385FF;
+  }
+  .avatar-upload-btn {
+    margin-top: 25upx;
+    width: 30vw;
+  }
 }
 </style>

+ 8 - 0
ghsApp/src/api/shop/index.js

@@ -55,6 +55,14 @@ export const updateShop = data => {
 	return https.post('/shop/update', data)
 }
 
+/** *
+ * 修改门店的头像
+ */
+export const updateShopAvatar = data => {
+	return https.post('/shop/update-avatar', data)
+}
+
+
 /** *
  * 添加门店
  */