Browse Source

basic 8.20更新

wangcy 2 months ago
parent
commit
8d385bc198

+ 18 - 8
commons/basic/Index.ets

@@ -1,19 +1,29 @@
+export { pushMessageUtil } from './src/main/ets/utils/NoticeUtil'
+
+export { yTPreferences } from './src/main/ets/utils/YTPreferencesUtil'
+
+export { yTToast } from './src/main/ets/utils/YTToast'
+
+export { PanGrid } from './src/main/ets/components/generalComp/PanGrid'
+
+
 export { YTPhotoHelper } from './src/main/ets/utils/YTPhotoHelper'
 
-export { permissionController } from './src/main/ets/utils/PermissionControl'
 
 export { YTUserRequest } from './src/main/ets/apis/YTUserRequest'
 
-export { YTDate } from './src/main/ets/utils/FormatDate'
 
-export { AppStorageKeyCollect } from './src/main/ets/constants'
+export { ScanCodeUtil } from './src/main/ets/utils/ScanCodeUtil'
+
+export { YTDate } from './src/main/ets/utils/YTDate'
+
+export * from './src/main/ets/constants'
+
 
 export * from '@ibestservices/ibest-ui'
 
 export { reviseImgHeaderBuilder } from './src/main/ets/components/generalComp/ReviseImgHeaderBuilder'
 
-export { takePicture } from './src/main/ets/utils/TakePicture'
-
 export { copyText } from './src/main/ets/utils/CopyText'
 
 export { Log as YTLog } from '@abner/log'
@@ -24,12 +34,14 @@ export { ShowBannerAd } from "./src/main/ets/components/adComp/ShowBannerAd"
 
 export { BannerAd } from "./src/main/ets/ads/BannerAd"
 
+
 export { ShowJHRewardAd } from "./src/main/ets/components/adComp/ShowJHRewardAd"
 
 export { jHStartAd } from "./src/main/ets/ads/StartAd"
 
 export { AdStatus } from "./src/main/ets/constants"
 
+export { permissionController } from "./src/main/ets/utils/PermissionControl"
 
 export { YTRequest } from "./src/main/ets/apis/YTRequest"
 
@@ -38,14 +50,11 @@ export { HuaweiAuthPlugin } from "./src/main/ets/utils/HuaWeiAuthPlugin"
 
 export { userInfo, UserInfo } from "./src/main/ets/models/UserInfo"
 
-export { yTToast } from "./src/main/ets/utils/YTToast"
 
 export { YTButton } from "./src/main/ets/components/generalComp/YTButton"
 
 export { YTHeader } from "./src/main/ets/components/generalComp/YTHeader"
 
-export { Upload } from "./src/main/ets/utils/UploadFile"
-
 export { YTAvoid } from "./src/main/ets/utils/YTAvoid"
 
 export { yTRouter } from "./src/main/ets/utils/YTRouter"
@@ -76,3 +85,4 @@ export * from './src/main/ets/models'
 
 
 
+

+ 38 - 8
commons/basic/src/main/ets/apis/YTRequest.ets

@@ -1,19 +1,22 @@
 import axios, {
   AxiosError,
   AxiosHeaders,
+  AxiosProgressEvent,
   AxiosRequestConfig,
   AxiosResponse,
+  FormData,
   InternalAxiosRequestConfig
 } from '@ohos/axios';
-import { IBestToast, YTLog } from '../../../../Index';
+import { IBestToast, ReqString, YTLog } from '../../../../Index';
 import { AppStorageKeyCollect } from '../constants';
 import { userInfo } from '../models/UserInfo';
 import { yTRouter } from '../utils/YTRouter';
 
 
-// export const baseURL: string = 'https://hm-test.ytpm.net/prod-api'
+// export const baseURL: string = 'https://hm.ytpm.net/prod-warhouse'
 
-export const baseURL: string = 'https://hm.ytpm.net/prod-warhouse'
+
+export const baseURL: string = 'http://192.168.1.160:48098'
 
 export const instance = axios.create({
   baseURL,
@@ -27,6 +30,8 @@ instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
   if (AppStorage.get<string>(AppStorageKeyCollect.TOKEN)) {
     config.headers.Authorization = AppStorage.get<string>(AppStorageKeyCollect.TOKEN)
   }
+  YTLog.info(config.data, '请求参数')
+
   return config;
 }, (error: AxiosError) => {
   // 对请求错误做些什么
@@ -41,9 +46,14 @@ instance.interceptors.response.use((response: AxiosResponse) => {
   YTLog.info(response)
   // 对响应错误做点什么
   if (response.data.code == 401) {
+    if (AppStorage.get<string>(AppStorageKeyCollect.TOKEN)) {
+      IBestToast.show("登录过期,请重新登录")
+    } else {
+      IBestToast.show("请先登录哦")
+    }
     userInfo.logout()
     yTRouter.router2LoginPage()
-    return Promise.reject(response.data);
+    return Promise.reject('401');
   }
   if (response.data.code == 500) {
     IBestToast.show({ message: response.data.msg, type: "fail" })
@@ -64,25 +74,45 @@ instance.interceptors.response.use((response: AxiosResponse) => {
 
 
 export class YTRequest {
-  static get<T>(url: string, params?: Record<string, string | number | boolean>, headers?: Record<string, string>) {
+  static get<T>(url: string, params?: ESObject,
+    headers?: Record<string, string>) {
     return instance.get<null, T, null>(url, { params, headers })
   }
 
-  static post<T, D>(url: string, data?: D, params?: Record<string, string | number | boolean>, headers?: AxiosHeaders) {
+  static post<T, D = ESObject>(url: string, data?: D, params?: ESObject,
+    headers?: AxiosHeaders) {
     return instance.post<null, T, D>(url, data, { params, headers })
   }
 
-  static delete<T>(url: string, params?: Record<string, string | number | boolean> | object, headers?: AxiosHeaders) {
+  static delete<T>(url: string, params?: ESObject, headers?: AxiosHeaders) {
     return instance.delete<null, T, null>(url, { params, headers })
   }
 
-  static put<T, D>(url: string, data?: D, params?: Record<string, string | number | boolean>, headers?: AxiosHeaders) {
+  static put<T, D>(url: string, data?: D, params?: ESObject, headers?: AxiosHeaders) {
     return instance.put<null, T, D>(url, data, { params, headers })
   }
 
   static upPost<T, D>(url: string, data: D, configs?: AxiosRequestConfig<D>) {
     return instance.post<string, T, D>(url, data, configs)
   }
+
+  //上传文件
+  static uploadFile(context: Context, fullpath: string, success: (url: string) => void) {
+    const formData = new FormData()
+    formData.append('file', fullpath)
+    YTRequest.upPost<ReqString, FormData>('/common/upload', formData, {
+      headers: { 'Content-Type': 'multipart/form-data' },
+      context,
+      onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
+        YTLog.info(progressEvent && progressEvent.loaded && progressEvent.total ?
+          Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%', 'uploadFile');
+      }
+    })
+      .then(res => {
+        const url = res['url']
+        success(url)
+      })
+  }
 }
 
 

+ 31 - 19
commons/basic/src/main/ets/apis/YTUserRequest.ets

@@ -7,7 +7,7 @@ import { yTRouter } from '../utils/YTRouter'
 import { YTRequest } from './YTRequest'
 import { YTLog } from '../../../../Index'
 import { AxiosProgressEvent, FormData } from '@ohos/axios'
-import { YTDate } from '../utils/FormatDate'
+import { YTDate } from '../utils/YTDate'
 import { HuaweiAuthPlugin } from '../utils/HuaWeiAuthPlugin'
 
 //用户相关api
@@ -110,6 +110,9 @@ export class YTUserRequest extends YTRequest {
         .catch((e: Error) => {
           YTLog.error(e)
           IBestToast.hide()
+          setTimeout(() => {
+            IBestToast.show({ message: '网络错误', type: 'fail' })
+          }, 50)
         })
     } catch (e) {
       YTLog.error(e)
@@ -130,23 +133,6 @@ export class YTUserRequest extends YTRequest {
       })
   }
 
-  //上传文件
-  static uploadFile(context: Context, fullpath: string, success: (url: string) => void) {
-    const formData = new FormData()
-    formData.append('file', fullpath)
-    YTUserRequest.upPost<ReqString, FormData>('/common/upload', formData, {
-      headers: { 'Content-Type': 'multipart/form-data' },
-      context,
-      onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
-        YTLog.info(progressEvent && progressEvent.loaded && progressEvent.total ?
-          Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%', 'uploadFile');
-      }
-    })
-      .then(res => {
-        const url = res['url']
-        success(url)
-      })
-  }
 
   // 修改用户头像
   static uploadHeadImg(context: Context, fullpath: string, success: () => void) {
@@ -194,7 +180,7 @@ export class YTUserRequest extends YTRequest {
     YTUserRequest.post<null, ReqString>(`/warehouseBack/saveQuestion`, {
       'backQuestion': des,
       'createBy': createBy,
-      'createTime': new YTDate().formatDate(),
+      'createTime': new YTDate().formatDate('-', true),
     })
       .then(() => {
         IBestToast.show("反馈成功")
@@ -204,4 +190,30 @@ export class YTUserRequest extends YTRequest {
         YTLog.error(e)
       })
   }
+
+
+  //账号注销/warehouseApUser/logout
+  static logout(result?: ResultCallBack<undefined>) {
+    YTUserRequest.post<null>(`/warehouseApUser/logout`)
+      .then(() => {
+        userInfo.logout()
+        result?.()
+      })
+      .catch((e: Error) => {
+        YTLog.error(e)
+      })
+  }
+
+  //像后端推送pushToken
+  static savePushToken(param: UserInfo, result: ResultCallBack<boolean>) {
+
+
+    YTUserRequest.post<boolean>('/warehouseApUser/savePushToken', param)
+      .then(res => {
+        result(res)
+      })
+      .catch((err: Error) => {
+        result(undefined, err)
+      })
+  }
 }

+ 348 - 0
commons/basic/src/main/ets/components/generalComp/PanGrid.ets

@@ -0,0 +1,348 @@
+import curves from '@ohos.curves'
+import { util } from '@kit.ArkTS'
+import { YTLog } from '../../../../../Index'
+
+@Component
+export struct PanGrid {
+  /**
+   * @description 需要渲染的数组
+   * @type extends BasicModel
+   */
+  @Prop @Require @Watch('changeList') displayArr: ESObject[]
+  /**
+   * @description 需要传入渲染的结构
+   */
+  @BuilderParam @Require gridItem: (_: ESObject, index: number) => void
+  /**
+   * @description grid的列数 两列示例: '1fr 1fr' 不支持动态传入
+   */
+  @Require columnsTemplate: string
+  sortOrder: string = 'sortOrder'
+  //完成
+  @Require onFinishCallBack: (arr: ESObject[]) => void
+  @State private dragItemId: number | string = -1
+  @State private scaleItemId: number | string = -1
+  @State private offsetX: number = 0
+  @State private offsetY: number = 0
+  private columnsCount: number = 0
+  private dragRefOffsetx: number = 0
+  private dragRefOffsety: number = 0
+  private FIX_VP_X: number = 108
+  private FIX_VP_Y: number = 120
+  private firstGetArea: boolean = true
+  private isMove: boolean = false
+  //用户传入的数组中是否有id
+  private scroller: Scroller = new Scroller()
+  //使用回调获取Scroller空值grid行为
+  onPanGridAppear = (_: Scroller) => {
+  }
+
+  aboutToAppear() {
+    this.columnsCount = this.columnsTemplate.split(' ').length
+
+
+    this.onPanGridAppear(this.scroller)
+  }
+
+  changeList() {
+    this.displayArr.forEach((item: ESObject) => {
+      if (item.id == undefined) {
+        item.id = util.generateRandomUUID()
+        item.haveId = false
+      }
+    })
+    if (this.isMove) {
+      return
+    }
+    // this.resetStates()
+  }
+
+  build() {
+    Column() {
+      Grid(this.scroller) {
+        ForEach(this.displayArr, (item: ESObject, index: number) => {
+          GridItem() {
+            this.gridItem(item, index)
+          }
+          .backgroundColor(Color.Transparent)
+          .shadow(this.dragItemId == item.id ? {
+            radius: 20, // 模糊半径(对应 20dp)
+            color: '#0F000000', // 阴影颜色
+            offsetX: 0, // 水平偏移
+            offsetY: 0       // 垂直偏移
+          } : undefined)
+          // .borderRadius(16)
+          .onAreaChange(this.firstGetArea ? (_, newArea) => {
+            this.FIX_VP_X = newArea.width as number
+            this.FIX_VP_Y = newArea.height as number
+
+          } : undefined)
+          // 指定固定GridItem不响应事件
+          // .hitTestBehavior(this.isDraggable(this.displayArr.indexOf(item)) ? HitTestMode.Default : HitTestMode.None)
+          // .scale({ x: this.scaleItemId == item.id ? 1.05 : 1, y: this.scaleItemId == item.id ? 1.05 : 1 })
+          .zIndex(this.dragItemId == item.id ? 1 : 0)
+          .translate(this.dragItemId == item.id ? { x: this.offsetX, y: this.offsetY } : { x: 0, y: 0 })
+          .gesture(
+            // 以下组合手势为顺序识别,当长按手势事件未正常触发时则不会触发拖动手势事件
+            GestureGroup(GestureMode.Sequence,
+              LongPressGesture({ repeat: true })
+                .onAction((event?: GestureEvent) => {
+                  this.getUIContext()?.animateTo({ curve: Curve.Friction, duration: 300 }, () => {
+                    this.scaleItemId = item.id
+                  })
+                })
+                .onActionEnd(() => {
+                  this.getUIContext()?.animateTo({ curve: Curve.Friction, duration: 300 }, () => {
+                    this.scaleItemId = -1
+                  })
+                }),
+              PanGesture({ fingers: 1, direction: null, distance: 0 })
+                .onActionStart(() => {
+                  this.isMove = true
+                  this.dragItemId = item.id
+                  this.dragRefOffsetx = 0
+                  this.dragRefOffsety = 0
+                })
+                .onActionUpdate((event: GestureEvent) => {
+                  this.offsetY = event.offsetY - this.dragRefOffsety
+                  this.offsetX = event.offsetX - this.dragRefOffsetx
+                  this.getUIContext()?.animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
+                    let index = this.displayArr.findIndex((item: ESObject) => item.id == this.dragItemId)
+                    if (this.offsetY >= this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44) &&
+                      !this.isLastRow(index)) {
+                      //向下滑
+                      this.down(index)
+                    } else if (this.offsetY <= -this.FIX_VP_Y / 2 && (this.offsetX <= 44 && this.offsetX >= -44) &&
+                      !this.isFirstRow(index)) {
+                      //向上滑
+                      this.up(index)
+                    } else if (this.offsetX >= this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50) &&
+                      !this.isLastColumn(index)) {
+                      //向右滑
+                      this.right(index)
+                    } else if (this.offsetX <= -this.FIX_VP_X / 2 && (this.offsetY <= 50 && this.offsetY >= -50) &&
+                      !this.isFirstColumn(index)) {
+                      //向左滑
+                      this.left(index)
+                    } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 &&
+                      !this.isLastRow(index) && !this.isLastColumn(index)) {
+                      //向右下滑
+                      this.lowerRight(index)
+                    } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2 &&
+                      !this.isFirstRow(index) && !this.isLastColumn(index)) {
+                      //向右上滑
+                      this.upperRight(index)
+                    } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 &&
+                      !this.isLastRow(index) && !this.isFirstColumn(index)) {
+                      //向左下滑
+                      this.lowerLeft(index)
+                    } else if (this.offsetX <= -this.FIX_VP_X / 2 && this.offsetY <= -this.FIX_VP_Y / 2 &&
+                      !this.isFirstRow(index) && !this.isFirstColumn(index)) {
+                      //向左上滑
+                      this.upperLeft(index)
+                    } else if (this.offsetX >= this.FIX_VP_X / 2 && this.offsetY >= this.FIX_VP_Y / 2 &&
+                    this.isLastRow(index) && this.isFirstColumn(index)) {
+                      //向右下滑(右下角为空)
+                      this.down(index)
+                    }
+                  }
+                  )
+                })
+                .onActionEnd(() => {
+                  this.getUIContext()?.animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
+                    this.dragItemId = -1
+                  })
+                  this.getUIContext()?.animateTo({
+                    curve: curves.interpolatingSpring(14, 1, 170, 17), delay: 150
+                  }, () => {
+                    this.scaleItemId = -1
+                  })
+                  // 更新sortOrder
+                  this.updateSortOrder()
+                  this.isMove = false
+                  //返回排序后的数组
+                  this.onFinishCallBack((() => {
+                    YTLog.info(this.displayArr, '删除id')
+                    this.displayArr.forEach((item: ESObject) => {
+                      //排除undefined的情况
+                      if (item.haveId == false) {
+                        item.id = undefined
+                      }
+                      item.haveId = undefined
+                    })
+                    YTLog.info(this.displayArr, '删除id')
+                    return this.displayArr
+                  })())
+
+                })
+            )
+              .onCancel(() => {
+                this.getUIContext()?.animateTo({ curve: curves.interpolatingSpring(0, 1, 400, 38) }, () => {
+                  this.dragItemId = -1
+                })
+                this.getUIContext()?.animateTo({
+                  curve: curves.interpolatingSpring(14, 1, 170, 17)
+                }, () => {
+                  this.scaleItemId = -1
+                })
+              })
+          )
+        }, (item: ESObject, _: number) => {
+          // 使用更稳定的key,优先使用id,其次使用sortOrder,最后使用JSON.stringify
+          return JSON.stringify(item);
+        })
+      }
+      .width('100%%')
+      .editMode(true)
+      .scrollBar(BarState.Off)
+      .columnsTemplate(this.columnsTemplate)
+      .rowsGap(8)
+
+    }
+    .width('100%')
+    .padding({ top: 5 })
+  }
+
+  // 重置所有状态
+  private resetStates(): void {
+    this.dragItemId = -1
+    this.scaleItemId = -1
+    this.offsetX = 0
+    this.offsetY = 0
+    this.dragRefOffsetx = 0
+    this.dragRefOffsety = 0
+  }
+
+  private itemMove(index: number, newIndex: number): void {
+    if (!this.isDraggable(newIndex)) {
+      return
+    }
+    let tmp: ESObject[] = this.displayArr.splice(index, 1)
+    this.displayArr.splice(newIndex, 0, tmp[0])
+  }
+
+  //向下滑
+  private down(index: number): void {
+    // 指定固定GridItem不响应事件
+    if (!this.isDraggable(index + this.columnsCount)) {
+      return
+    }
+    this.offsetY -= this.FIX_VP_Y
+    this.dragRefOffsety += this.FIX_VP_Y
+    this.itemMove(index, index + this.columnsCount)
+  }
+
+  //向上滑
+  private up(index: number): void {
+    if (!this.isDraggable(index - this.columnsCount)) {
+      return
+    }
+    this.offsetY += this.FIX_VP_Y
+    this.dragRefOffsety -= this.FIX_VP_Y
+    this.itemMove(index, index - this.columnsCount)
+  }
+
+  //向左滑
+  private left(index: number): void {
+    if (!this.isDraggable(index - 1)) {
+      return
+    }
+    this.offsetX += this.FIX_VP_X
+    this.dragRefOffsetx -= this.FIX_VP_X
+    this.itemMove(index, index - 1)
+  }
+
+  //向右滑
+  private right(index: number): void {
+    if (!this.isDraggable(index + 1)) {
+      return
+    }
+    this.offsetX -= this.FIX_VP_X
+    this.dragRefOffsetx += this.FIX_VP_X
+    this.itemMove(index, index + 1)
+  }
+
+  //向右下滑
+  private lowerRight(index: number): void {
+    if (!this.isDraggable(index + this.columnsCount + 1)) {
+      return
+    }
+    this.offsetX -= this.FIX_VP_X
+    this.dragRefOffsetx += this.FIX_VP_X
+    this.offsetY -= this.FIX_VP_Y
+    this.dragRefOffsety += this.FIX_VP_Y
+    this.itemMove(index, index + this.columnsCount + 1)
+  }
+
+  //向右上滑
+  private upperRight(index: number): void {
+    if (!this.isDraggable(index - this.columnsCount + 1)) {
+      return
+    }
+    this.offsetX -= this.FIX_VP_X
+    this.dragRefOffsetx += this.FIX_VP_X
+    this.offsetY += this.FIX_VP_Y
+    this.dragRefOffsety -= this.FIX_VP_Y
+    this.itemMove(index, index - this.columnsCount + 1)
+  }
+
+  //向左下滑
+  private lowerLeft(index: number): void {
+    const targetIndex = index + this.columnsCount - 1; // 正确目标索引是 2
+    if (!this.isDraggable(targetIndex)) { // 检查目标索引而非 index+2
+      return
+    }
+    this.offsetX += this.FIX_VP_X
+    this.dragRefOffsetx -= this.FIX_VP_X
+    this.offsetY -= this.FIX_VP_Y
+    this.dragRefOffsety += this.FIX_VP_Y
+    this.itemMove(index, targetIndex) // 使用计算后的目标索引
+  }
+
+  //向左上滑
+  private upperLeft(index: number): void {
+    if (!this.isDraggable(index - this.columnsCount - 1)) {
+      return
+    }
+    this.offsetX += this.FIX_VP_X
+    this.dragRefOffsetx -= this.FIX_VP_X
+    this.offsetY += this.FIX_VP_Y
+    this.dragRefOffsety -= this.FIX_VP_Y
+    this.itemMove(index, index - this.columnsCount - 1)
+  }
+
+  private isDraggable(index: number): boolean {
+    return index < this.displayArr.length
+  }
+
+  // 新增辅助方法:检查当前项是否在最后一行
+  private isLastRow(index: number): boolean {
+    const rowIndex = Math.floor(index / this.columnsCount);
+    const totalRows = Math.ceil(this.displayArr.length / this.columnsCount);
+    return rowIndex === totalRows - 1;
+  }
+
+  // 检查是否在第一行
+  private isFirstRow(index: number): boolean {
+    return Math.floor(index / this.columnsCount) === 0;
+  }
+
+  // 检查是否在最后一列
+  private isLastColumn(index: number): boolean {
+    return index % this.columnsCount === this.columnsCount - 1;
+  }
+
+  // 检查是否在第一列
+  private isFirstColumn(index: number): boolean {
+    return index % this.columnsCount === 0;
+  }
+
+  // 更新sortOrder字段
+  private updateSortOrder(): void {
+    for (let i = 0; i < this.displayArr.length; i++) {
+      this.displayArr[i][this.sortOrder] = (i + 1).toString();
+    }
+  }
+}
+
+

+ 43 - 0
commons/basic/src/main/ets/constants/index.ets

@@ -38,4 +38,47 @@ export enum AppStorageKeyCollect {
    * @description 验证码登录手机号与验证码
    */
   CAPTCHA_LOGIN = 'captchaLogin'
+}
+
+export enum EmitterKeyCollection {
+  /**
+   * @description 刷新已经渲染的食物列表
+   */
+  REFRESH_FOOD_LIST = 'refreshFoodList',
+
+  /**
+   * @description 删除并刷新文件夹
+   */
+  DELETE_AND_REFRESH_FOLDER = 'deleteAndRefreshFolder',
+
+
+  /**
+   * @description 登录
+   */
+  LOGIN = 'userLoginIn',
+
+  /**
+   * @description 登出
+   */
+  LOGOUT = 'UserLogout',
+
+  /**
+   * @description 全选删除
+   */
+  GROUP_SELECTED_DELETE = 'groupSelected',
+
+  /**
+   * @description 选择项恢复初始状态
+   */
+  SELECTED_RESET = 'selectedReset',
+
+  /**
+   * @description 刷新日历数据
+   */
+  REFRESH_CALENDER_DATA = 'refreshCalenderData',
+
+  /**
+   * @description 刷新当前选中日期数据
+   */
+  REFRESH_CURRENT_DATE_DATA = 'refreshCurrentDateData',
 }

+ 49 - 23
commons/basic/src/main/ets/models/UserInfo.ets

@@ -1,5 +1,7 @@
+import { AppStorageKeyCollect, EmitterKeyCollection } from '../constants'
 import { emitter } from '@kit.BasicServicesKit'
-import { AppStorageKeyCollect } from '../constants'
+import { YTUserRequest } from '../apis/YTUserRequest'
+import { YTLog } from '../../../../Index'
 
 /**
  * @description 用户信息类,可结合AppStorage使用,实现响应式更换用户信息,使用时替换为后端传回的用户属性即可
@@ -17,6 +19,7 @@ export class UserInfo {
   private aiCount?: number
   private userId?: number
   private memberScore?: number
+  private declare pushToken: string
 
   private constructor() {
   }
@@ -37,35 +40,37 @@ export class UserInfo {
    * @param _userInfo
    */
   setUserInfoAndLogin(_userInfo: UserInfo) {
-    this.isLogin = true
+    userInfo.isLogin = true
     if (_userInfo.token) {
       userInfo.token = _userInfo.token
     }
-    this.memberEmail = _userInfo.memberEmail
-    this.memberIcon = _userInfo.memberIcon
-    this.memberName = _userInfo.memberName
-    this.userId = _userInfo.userId
-    this.memberScore = _userInfo.memberScore
-    this.aiCount = _userInfo.aiCount
-    this.memberPhone = _userInfo.memberPhone
-    emitter.emit('refreshList')
-    AppStorage.setOrCreate(UserInfo.KEY, this)
+    userInfo.memberEmail = _userInfo.memberEmail
+    userInfo.memberIcon = _userInfo.memberIcon
+    userInfo.memberName = _userInfo.memberName
+    userInfo.userId = _userInfo.userId
+    userInfo.memberScore = _userInfo.memberScore
+    userInfo.aiCount = _userInfo.aiCount
+    userInfo.memberPhone = _userInfo.memberPhone
+
+    emitter.emit(EmitterKeyCollection.LOGIN)
+    AppStorage.setOrCreate(UserInfo.KEY, userInfo)
   }
 
   /**
    * @description 登出并清空用户信息
    */
   logout() {
-    this.isLogin = false
-    this.token = undefined
-    this.memberEmail = undefined
-    this.memberIcon = undefined
-    this.memberName = undefined
-    this.userId = undefined
-    this.memberScore = undefined
-    this.aiCount = undefined
-    this.memberPhone = undefined
-    AppStorage.setOrCreate(UserInfo.KEY, this)
+    userInfo.isLogin = false
+    userInfo.token = undefined
+    userInfo.memberEmail = undefined
+    userInfo.memberIcon = undefined
+    userInfo.memberName = undefined
+    userInfo.userId = undefined
+    userInfo.memberScore = undefined
+    userInfo.aiCount = undefined
+    userInfo.memberPhone = undefined
+    AppStorage.setOrCreate(UserInfo.KEY, userInfo)
+    emitter.emit(EmitterKeyCollection.LOGOUT)
     AppStorage.setOrCreate(AppStorageKeyCollect.TOKEN, undefined)
   }
 
@@ -81,7 +86,6 @@ export class UserInfo {
     return this.token
   }
 
-
   setToken(token: string) {
     this.token = token
     AppStorage.setOrCreate<string>(AppStorageKeyCollect.TOKEN, token)
@@ -89,10 +93,13 @@ export class UserInfo {
     return this
   }
 
-  getHeadImg() {
+  getHeadImg(defaultIcon?: ResourceStr) {
     if (this.memberIcon) {
       return this.memberIcon
     }
+    if (defaultIcon) {
+      return defaultIcon
+    }
     return $r('app.media.app_icon')
   }
 
@@ -177,6 +184,25 @@ export class UserInfo {
     AppStorage.setOrCreate(UserInfo.KEY, this)
     return this
   }
+
+  setPushToken(pushToken: string) {
+    this.pushToken = pushToken
+    return this
+  }
+
+  pushPushTokenToBackEnd(success: () => void) {
+    YTUserRequest.savePushToken(this, (res, err) => {
+      if (!err && res) {
+        YTLog.info(res)
+        success()
+      } else {
+        YTLog.error(err)
+      }
+    })
+  }
 }
 
 export const userInfo = UserInfo.getInstance()
+
+
+

+ 1 - 1
commons/basic/src/main/ets/models/index.ets

@@ -1,6 +1,6 @@
 import { LoginCollect } from './LoginCollect'
 
-export interface BasicType<T> {
+export interface BasicType<T = undefined> {
   src?: ResourceStr,
   acSrc?: ResourceStr,
   text?: string,

+ 81 - 0
commons/basic/src/main/ets/utils/NoticeUtil.ets

@@ -0,0 +1,81 @@
+import { common } from '@kit.AbilityKit';
+import { notificationManager } from '@kit.NotificationKit';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { YTLog } from '../../../../Index';
+import { pushService } from '@kit.PushKit';
+import { userInfo } from '../models/UserInfo';
+
+class PushMessageUtil {
+  private static instance: PushMessageUtil
+  private isFirstRequestPermission: boolean = true
+  private declare context: common.UIAbilityContext
+  private readonly setDataPersistenceKey: string = 'setDataPersistenceKey'
+
+  private constructor() {
+  }
+
+  static getInstance() {
+    if (!PushMessageUtil.instance) {
+      PushMessageUtil.instance = new PushMessageUtil()
+    }
+    return PushMessageUtil.instance
+  }
+
+  init(context: common.UIAbilityContext) {
+    PersistentStorage.persistProp<boolean>(this.setDataPersistenceKey, this.isFirstRequestPermission)
+    this.context = context
+    this.isFirstRequestPermission = AppStorage.get<boolean>(this.setDataPersistenceKey) ?? true
+  }
+
+  //请求权限+推送token
+  pushMessage(success: () => void) {
+    notificationManager.isNotificationEnabled((err, enable) => {
+      if (enable && !err) {
+        //像后端推送pushToken
+        this.pushToken(success)
+      } else {
+        if (this.isFirstRequestPermission) {
+          notificationManager.requestEnableNotification(this.context)
+            .then(() => {
+              this.pushToken(success)
+            })
+            .catch((err: BusinessError) => {
+              if (1600004 == err.code) {
+                YTLog.error("requestEnableNotification refused" + err.code)
+              } else {
+                YTLog.error("requestEnableNotification failed:" + err.code + err.message)
+              }
+            })
+            .finally(() => {
+              this.isFirstRequestPermission = false
+            })
+        } else {
+          notificationManager.openNotificationSettings(this.context)
+            .then(() => {
+              this.pushMessage(success)
+            })
+            .catch((err: BusinessError) => {
+              if (1600004 == err.code) {
+                YTLog.error("requestEnableNotification refused" + err.code)
+              } else {
+                YTLog.error("requestEnableNotification failed:" + err.code + err.message)
+              }
+            });
+
+        }
+      }
+    })
+  }
+
+  private pushToken(success: () => void) {
+    pushService.getToken((err, token) => {
+      if (token && !err) {
+        userInfo.setPushToken(token).pushPushTokenToBackEnd(success)
+      } else {
+        YTLog.error(err)
+      }
+    });
+  }
+}
+
+export const pushMessageUtil = PushMessageUtil.getInstance()

+ 23 - 10
commons/basic/src/main/ets/utils/PermissionControl.ets

@@ -1,16 +1,17 @@
 import { abilityAccessCtrl, bundleManager, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
 
-export class PermissionControl {
+class PermissionControl {
   private declare static instance: PermissionControl
   private tokenID: number = 0
   //记录已申请权限,方便到时候调用checkPermission时传参
-  private permissions: Permissions[] = []
+  // private permissions: Permissions[] = []
   //上一次使用checkPermission校验的权限
-  private lastPermission?: Permissions
+  private declare lastPermission: Permissions
   private context?: Context
-  private atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
+  private atManager: abilityAccessCtrl.AtManager
 
   private constructor() {
+    this.atManager = abilityAccessCtrl.createAtManager()
   }
 
   static getInstance() {
@@ -28,21 +29,33 @@ export class PermissionControl {
   }
 
   //申请权限
-  askPermission(permissions: Permissions[], callback: (res?: PermissionRequestResult, err?: Error) => void) {
-    this.permissions = permissions
+  askPermissions(permissions: Permissions[], result: (res?: PermissionRequestResult, err?: Error) => void) {
     this.atManager.requestPermissionsFromUser(this.context, permissions, (err, data) => {
       if (!err && data) {
-        callback(data)
+        result(data)
       } else {
-        callback(undefined, err)
+        result(undefined, err)
       }
     })
   }
 
   //二次申请权限 不传参数就是上次校验的权限
-  secondAskPermission(permission: Permissions | undefined = this.lastPermission) {
+  secondAskPermission(result?: (flag: boolean, err?: Error) => void,
+    permission: Permissions[] = [this.lastPermission]) {
     if (permission) {
-      this.atManager.requestPermissionOnSetting(this.context, this.permissions)
+      this.atManager.requestPermissionOnSetting(this.context, permission)
+        .then((res) => {
+          let flag = true
+          res.forEach(item => {
+            if (item == -1) {
+              flag = false
+            }
+          })
+          result?.(flag)
+        })
+        .catch((err: Error) => {
+          result?.(false, err)
+        })
     }
   }
 

+ 85 - 0
commons/basic/src/main/ets/utils/ScanCodeUtil.ets

@@ -0,0 +1,85 @@
+import { BusinessError } from '@kit.BasicServicesKit';
+import { customScan, scanBarcode, scanCore } from '@kit.ScanKit';
+import { permissionController } from './PermissionControl';
+import { YTLog } from '../../../../Index';
+
+interface ScanCodeUtilInterface {
+  viewControl: customScan.ViewControl
+  scanOptions?: scanBarcode.ScanOptions
+}
+
+export class ScanCodeUtil {
+  private viewControl: customScan.ViewControl
+  private scanOptions: scanBarcode.ScanOptions
+  private isAuthorization: boolean = false
+
+  constructor(options: ScanCodeUtilInterface) {
+    this.viewControl = options.viewControl
+    if (options.scanOptions) {
+      this.scanOptions = options.scanOptions
+    } else {
+      this.scanOptions = {
+        scanTypes: [scanCore.ScanType.ALL],
+        enableMultiMode: true,
+        enableAlbum: true
+      }
+    }
+
+
+    this.initCustomScan()
+
+  }
+
+  initCustomScan() {
+    try {
+      if (permissionController.checkPermission('ohos.permission.CAMERA')) {
+        customScan.init(this.scanOptions);
+        this.isAuthorization = true
+      } else {
+        permissionController.secondAskPermission((isAuthorization) => {
+          this.isAuthorization = isAuthorization
+        })
+      }
+
+    } catch (error) {
+      YTLog.error(error);
+    }
+  }
+
+  // customScan.ViewControl = {
+  //       width: this.cameraWidth,
+  //       height: this.cameraHeight,
+  //       surfaceId: surfaceId
+  //     };
+  startCustomScan(result: (res?: Array<scanBarcode.ScanResult>, err?: Error) => void): boolean {
+    if (this.isAuthorization) {
+      try {
+        customScan.start(this.viewControl).then((scanResult: Array<scanBarcode.ScanResult>) => {
+          YTLog.info(scanResult)
+          result(scanResult)
+        }).catch((error: BusinessError) => {
+          result(undefined, error)
+          YTLog.error(`Code: ${error.code}, message: ${error.message}`)
+        })
+      } catch (error) {
+        result(undefined, error)
+        YTLog.error(`Code: ${error.code}, message: ${error.message}`)
+      }
+
+    } else {
+      result(undefined, new Error('用户未授权相机权限'))
+      YTLog.error('用户未授权相机权限')
+    }
+    return this.isAuthorization
+  }
+
+
+  //在不需要时需要及时释放相机资源
+  stopAndReleaseCustomScan() {
+    customScan.stop()
+      .then(() => {
+        customScan.release()
+      })
+
+  }
+}

+ 0 - 22
commons/basic/src/main/ets/utils/TakePicture.ets

@@ -1,22 +0,0 @@
-import { fileIo, fileUri } from '@kit.CoreFileKit';
-import { camera, cameraPicker as picker } from '@kit.CameraKit';
-
-export async function takePicture(context: Context) {
-  let pathDir = context.filesDir;
-  let fileName = `${new Date().getTime()}`
-  let filePath = pathDir + `/${fileName}.png`
-  fileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE);
-
-  let uri = fileUri.getUriFromPath(filePath);
-  let pickerProfile: picker.PickerProfile = {
-    cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,
-    saveUri: uri
-  };
-  let result: picker.PickerResult =
-    await picker.pick(getContext(), [picker.PickerMediaType.PHOTO], //(如果需要录像可以添加) picker.PickerMediaType.VIDEO
-      pickerProfile);
-  if (!result.resultUri) {
-    return Promise.reject('用户未拍照')
-  }
-  return filePath
-}

+ 0 - 70
commons/basic/src/main/ets/utils/UploadFile.ets

@@ -1,70 +0,0 @@
-import { photoAccessHelper } from '@kit.MediaLibraryKit'
-import { util } from '@kit.ArkTS'
-import { fileIo } from '@kit.CoreFileKit'
-import { YTLog } from '../../../../Index'
-
-
-export class Upload {
-  // static uploadImage(context: Context) {
-  //   const option = new photoAccessHelper.PhotoSelectOptions()
-  //   option.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
-  //   option.maxSelectNumber = 5 // 设置最多选择5张
-  //   option.isOriginalSupported = true
-  //
-  //   const picker = new photoAccessHelper.PhotoViewPicker()
-  //   picker.select(option)
-  //     .then(async res => { // 改为async/await语法
-  //       try {
-  //         const formData = new FormData()
-  //
-  //         // 并行处理多图
-  //         await Promise.all(res.photoUris.map(async (uri, index) => {
-  //           const photoName = util.generateRandomUUID()
-  //           const photoType = '.' + uri.split('.').pop()
-  //           const fullPath = context.cacheDir + '/' + photoName + photoType
-  //
-  //           const photo = fileIo.openSync(uri)
-  //           try {
-  //             await fileIo.copyFile(photo.fd, fullPath)
-  //             formData.append('file' + index, 'internal://cache/' + photoName + photoType)
-  //           } finally {
-  //             fileIo.closeSync(photo.fd) // 确保关闭文件描述符
-  //           }
-  //         }))
-  //
-  //
-  //         // 统一提交所有文件
-  //         // 这里添加实际的上传代码,例如:
-  //         // const response = await axios.post('your_api_url', formData)
-  //         // YTLog.info('Upload success:' + JSON.stringify(response.data))
-  //
-  //       } catch (err) {
-  //         YTLog.error('Upload failed:' + JSON.stringify(err))
-  //       }
-  //     })
-  // }
-
-  static selectImage(context: Context, isReady: (fullPath: string) => void) {
-    const option = new photoAccessHelper.PhotoSelectOptions()
-    option.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
-    option.maxSelectNumber = 1
-    const picker = new photoAccessHelper.PhotoViewPicker()
-    picker.select(option)
-      .then(res => {
-        const photoName = util.generateRandomUUID()
-        const photoType = '.' + res.photoUris[0].split('.').pop()
-        const fullPath = context.cacheDir + '/' + photoName + photoType
-        const photo = fileIo.openSync(res.photoUris[0])
-        try {
-          fileIo.copyFile(photo.fd, fullPath)
-            .then(() => {
-              YTLog.info(fullPath)
-              isReady(fullPath)
-            })
-        } catch (err) {
-          YTLog.error(err)
-        }
-      })
-  }
-}
-

+ 5 - 1
commons/basic/src/main/ets/utils/FormatDate.ets → commons/basic/src/main/ets/utils/YTDate.ets

@@ -15,7 +15,6 @@ export class YTDate extends Date {
     super(value)
   }
 
-
   /**
    * 将数字转换为中文周数表示(如:7 → "第七周")
    * @param weekNum - 周数数字(正整数)
@@ -74,6 +73,11 @@ export class YTDate extends Date {
     return weekdays[dayIndex];
   }
 
+  static getWeeks(concatenation: string = '') {
+    return [concatenation + "一", concatenation + "二", concatenation + "三", concatenation + "四",
+      concatenation + "五", concatenation + "六", concatenation + "日"]
+  }
+
   /**
    * 替换日期分隔符
    * @param separator - 新的分隔符

+ 41 - 0
commons/basic/src/main/ets/utils/YTPreferencesUtil.ets

@@ -0,0 +1,41 @@
+import { preferences } from '@kit.ArkData'
+
+class YTPreferences {
+  private static declare instance: YTPreferences
+  private preferencesName: string = 'preferencesName'
+  private declare preference: preferences.Preferences
+
+  private constructor() {
+  }
+
+  static getInstance() {
+    if (!YTPreferences.instance) {
+      YTPreferences.instance = new YTPreferences()
+    }
+    return YTPreferences.instance
+  }
+
+  init(context: Context) {
+    this.preference = preferences.getPreferencesSync(context, { name: this.preferencesName })
+  }
+
+  setData(key: string, data: ESObject) {
+    this.preference.put(key, data)
+    this.preference.flushSync()
+  }
+
+  getData(key: string): ESObject {
+    return this.preference.getSync(key, undefined)
+  }
+
+  removeData(key: string) {
+    this.preference.deleteSync(key)
+  }
+
+  clear() {
+    this.preference.clearSync()
+    this.preference.flushSync()
+  }
+}
+
+export const yTPreferences = YTPreferences.getInstance()

+ 0 - 232
commons/basic/src/main/ets/utils/YTRequest.ets

@@ -1,232 +0,0 @@
-import axios, {
-  AxiosError,
-  AxiosHeaders,
-  AxiosProgressEvent,
-  AxiosRequestConfig,
-  AxiosResponse,
-  FormData,
-  InternalAxiosRequestConfig
-} from '@ohos/axios';
-import { IBestToast, YTDate, YTLog, yTRouter } from '../../../../Index';
-import { AppStorageKeyCollect } from '../constants';
-import { ReqString } from '../models';
-import { userInfo, UserInfo } from '../models/UserInfo';
-import { HuaweiAuthPlugin } from './HuaWeiAuthPlugin';
-
-
-export const baseURL: string = 'https://hm.ytpm.net/prod-warhouse'
-
-export const instance = axios.create({
-  baseURL,
-  timeout: 5000
-})
-
-// 添加请求拦截器
-instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
-
-  // 对请求数据做点什么
-  if (AppStorage.get<string>(AppStorageKeyCollect.TOKEN)) {
-    config.headers.Authorization = AppStorage.get<string>(AppStorageKeyCollect.TOKEN)
-  }
-  return config;
-}, (error: AxiosError) => {
-  // 对请求错误做些什么
-
-  return Promise.reject(error);
-});
-
-
-// 添加响应拦截器
-instance.interceptors.response.use((response: AxiosResponse) => {
-  // 对响应数据做点什么
-  YTLog.info(response)
-  // 对响应错误做点什么
-  if (response.data.code == 401) {
-    userInfo.logout()
-    yTRouter.router2LoginPage()
-    return Promise.reject('401');
-  }
-
-  return response.data.data;
-}, (error: AxiosError) => {
-  YTLog.error(error)
-  setTimeout(() => {
-    IBestToast.hide()
-    setTimeout(() => {
-      IBestToast.show({ message: '请求超时,请检查网络' })
-    }, 100)
-  }, 1000)
-  return Promise.reject(error);
-});
-
-
-export class YTRequest {
-  private static productName: string = 'chat'
-
-  static get<T>(url: string, params?: Record<string, string | number | boolean>,
-    headers?: Record<string, string>): Promise<T> {
-    return instance.get<null, T, null>(url, { params, headers })
-  }
-
-  static post<T, D>(url: string, data?: D, params?: Record<string, string | number | boolean>, headers?: AxiosHeaders) {
-    return instance.post<null, T, D>(url, data, { params, headers })
-  }
-
-  static upPost<T, D>(url: string, data: D, configs?: AxiosRequestConfig<D>) {
-    return instance.post<string, T, D>(url, data, configs)
-  }
-
-  //获取验证码
-  static getCaptcha(phonenumber: string, success: (res: string) => void, fail: (err: Error) => void) {
-    YTRequest.post<ReqString, ReqString>(`/api/${YTRequest.productName}/member/sendSmsCode`,
-      { 'phonenumber': phonenumber })
-      .then(res => {
-        success(res['uuid'])
-      })
-      .catch((err: Error) => {
-        fail(err)
-      })
-  }
-
-  //手机号登录
-  static phonenumberLogin(param: ReqString) {
-    const uuid = AppStorage.get<string>('uuid')
-    if (uuid !== undefined) {
-      YTRequest.post<ReqString, ReqString>(`/api/${YTRequest.productName}/member/phoneLogin`, {
-        'phonenumber': param['phonenumber'],
-        'smsCode': param['captcha'],
-        'uuid': uuid
-      })
-        .then(res => {
-          userInfo.setToken(res[AppStorageKeyCollect.TOKEN])
-          YTRequest.refreshUserInfo(() => {
-            IBestToast.show({ message: '登录成功' })
-            yTRouter.routerBack()
-          })
-        })
-    }
-  }
-
-  //华为登录
-  static huaweiLogin() {
-    try {
-      IBestToast.showLoading()
-      HuaweiAuthPlugin.requestAuth()
-        .then(res => {
-          YTRequest.post<ReqString, ReqString>(`/api/${YTRequest.productName}/member/hmLogin`,
-            { 'code': res } as ReqString)
-            .then(data => {
-              const token = data['token']
-              userInfo.setToken(token)
-              YTRequest.refreshUserInfo((userInfo) => {
-                // YTLog.info(userInfo)
-                IBestToast.hide()
-                setTimeout(() => {
-                  IBestToast.show({ message: '登录成功' })
-                }, 100)
-                yTRouter.routerBack()
-              })
-            })
-            .catch((err: Error) => {
-              // AlertDialog.show({ message: JSON.stringify(err, null, 2) })
-              // IBestToast.hide()
-              YTLog.error(err)
-            })
-        })
-        .catch((e: Error) => {
-          // AlertDialog.show({ message: JSON.stringify(e, null, 2) })
-          YTLog.error(e)
-          // IBestToast.hide()
-        })
-    } catch (e) {
-      // AlertDialog.show({ message: JSON.stringify(e, null, 2) })
-      YTLog.error(e)
-      // IBestToast.hide()
-    }
-  }
-
-  //刷新用户信息
-  static refreshUserInfo(success?: (res: UserInfo) => void) {
-    YTRequest.post<UserInfo, null>(`/api/${YTRequest.productName}/member/info`)
-      .then(res => {
-        userInfo.setUserInfoAndLogin(res)
-        YTLog.info(userInfo)
-        success?.(res)
-      })
-  }
-
-  //上传文件
-  static uploadFile(context: Context, fullpath: string, success: (url: string) => void) {
-    const formData = new FormData()
-    formData.append('file', fullpath)
-    YTRequest.upPost<ReqString, FormData>('/common/upload', formData, {
-      headers: { 'Content-Type': 'multipart/form-data' },
-      context,
-      onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
-        YTLog.info(progressEvent && progressEvent.loaded && progressEvent.total ?
-          Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%', 'uploadFile');
-      }
-    })
-      .then(res => {
-        const url = res['url']
-        success(url)
-      })
-  }
-
-  // 修改用户头像
-  static uploadHeadImg(context: Context, fullpath: string, success: () => void) {
-    const formData = new FormData()
-    formData.append('file', fullpath)
-
-    YTRequest.upPost<ReqString, FormData>('/common/upload', formData, {
-      headers: { 'Content-Type': 'multipart/form-data' },
-      context,
-      onUploadProgress: (progressEvent: AxiosProgressEvent): void => {
-        YTLog.info(progressEvent && progressEvent.loaded && progressEvent.total ?
-          Math.ceil(progressEvent.loaded / progressEvent.total * 100) + '%' : '0%', 'uploadFile');
-      }
-    })
-      .then(res => {
-        const url = res['url']
-        YTRequest.post<null, ReqString>(`/api/${YTRequest.productName}/member/modifyMemberIcon`, { 'memberIcon': url })
-          .then(() => {
-            success()
-          })
-          .catch((e: Error) => {
-            YTLog.error(e)
-            // IBestToast.show({ message: '头像上传失败', type: 'fail' })
-          })
-      })
-      .catch((e: Error) => {
-        YTLog.error(e)
-      })
-  }
-
-  // 修改用户昵称
-  static changeNickname(name: string, success: () => void) {
-    YTRequest.post<null, ReqString>(`/api/${YTRequest.productName}/member/modifyMemberName`, { 'memberName': name })
-      .then(() => {
-        YTRequest.refreshUserInfo(() => {
-          success()
-        })
-      })
-  }
-
-  //问题反馈
-  static questionBack(des: string, createBy: string) {
-    YTRequest.post<null, ReqString>(`/api/${YTRequest.productName}/question/saveQuestion`, {
-      'backQuestion': des,
-      'createBy': createBy,
-      'createTime': new YTDate().formatDate(),
-    })
-      .then(() => {
-        IBestToast.show("反馈成功")
-        yTRouter.routerBack()
-      })
-      .catch((e: Error) => {
-        YTLog.error(e)
-      })
-  }
-}
-
-

+ 11 - 2
commons/basic/src/main/ets/utils/YTRouter.ets

@@ -1,6 +1,7 @@
+import { IBestToast } from '@ibestservices/ibest-ui'
 import { DelPhotoParam } from '../models'
 
-export class YTRouter extends NavPathStack {
+class YTRouter extends NavPathStack {
   private static declare instance: YTRouter
 
   private constructor() {
@@ -48,7 +49,10 @@ export class YTRouter extends NavPathStack {
     return yTRouter.getParamByName('AgreementPage').pop() as '关于我们' | '隐私政策' | '用户协议'
   }
 
-  router2LoginPage() {
+  router2LoginPage(needToast: boolean = false) {
+    if (needToast) {
+      IBestToast.show("请先登录哦~")
+    }
     yTRouter.pushPathByName('LoginPage', '')
   }
 
@@ -60,6 +64,11 @@ export class YTRouter extends NavPathStack {
     return yTRouter.getParamByName('DelPhotoPage').pop() as DelPhotoParam
   }
 
+  //UpdatePasswordPage
+  router2UpdatePasswordPage() {
+    yTRouter.pushPathByName("UpdatePasswordPage", '')
+  }
+
   routerBack() {
     yTRouter.pop()
   }

+ 11 - 5
commons/basic/src/main/ets/utils/YTToast.ets

@@ -22,7 +22,7 @@ class Params<T> implements BasicType<T> {
   loginType?: LoginCollect
   click?: () => void
 
-  constructor(item: BasicType<undefined> = {}) {
+  constructor(item: BasicType = {}) {
     this.src = item.src;
     this.text = item.text;
     this.index = item.index;
@@ -67,8 +67,8 @@ export class YTToast {
   }
 
   openToast(builder: WrappedBuilder<[
-    BasicType<undefined>
-  ]>, item: BasicType<undefined>) {
+    BasicType
+  ]>, item: BasicType) {
     this.contentNode =
       new ComponentContent(this.ctx, builder, new Params<undefined>(item));
     this.ctx.getPromptAction()
@@ -83,11 +83,11 @@ export class YTToast {
       })
   }
 
-  doubleConfirm(item: BasicType<undefined>) {
+  doubleConfirm(item: BasicType) {
     this.openToast(wrapBuilder(yTDoubleConfirm), item)
   }
 
-  agreePrivacy(item: BasicType<undefined>) {
+  agreePrivacy(item: BasicType) {
     this.openToast(wrapBuilder(agreePrivacy), item)
   }
 
@@ -126,6 +126,12 @@ export class YTToast {
         })
     }
   }
+
+  confirmDeleteFolder(sure: () => void) {
+    yTToast.doubleConfirm({
+      message: '删除该分类将会同时删除分类下所\n有信息', click: sure
+    })
+  }
 }
 
 export const yTToast = YTToast.getInstance()

+ 104 - 61
features/user/src/main/ets/views/Mine.ets

@@ -1,15 +1,23 @@
-import {
-  BasicType, copyText, IBestToast, userInfo, UserInfo, YTAvoid, YTLog, yTRouter
-} from 'basic'
+import { BasicType, IBestToast, userInfo, UserInfo, YTAvoid, YTLog, yTRouter } from 'basic'
 import { common, Want } from '@kit.AbilityKit'
 import { BusinessError } from '@kit.BasicServicesKit'
 import { BUNDLE_NAME } from 'BuildProfile'
+import { systemShare } from '@kit.ShareKit'
+import { uniformTypeDescriptor } from '@kit.ArkData'
 
 @Component
 export struct Mine {
   @StorageProp(YTAvoid.SAFE_TOP_KEY) safeTop: number = 0
   @StorageProp(UserInfo.KEY) userInfo: UserInfo = userInfo
-  setArr: Array<BasicType<undefined>> = [
+  setArr: Array<BasicType> = [
+    {
+      text: '分享给好友',
+      message: '去分享',
+      click: () => {
+        this.shareData()
+      },
+      src: $r('app.media.mine_right_arrow')
+    },
     {
       text: '意见反馈',
       click: () => {
@@ -19,7 +27,7 @@ export struct Mine {
           yTRouter.router2LoginPage()
         }
       },
-      src: $r('app.media.right_arrow')
+      src: $r('app.media.mine_right_arrow')
     },
     {
       text: '给个好评',
@@ -37,14 +45,14 @@ export struct Mine {
           IBestToast.show('出现未知错误,请稍后再试')
         });
       },
-      src: $r('app.media.right_arrow')
+      src: $r('app.media.mine_right_arrow')
     },
     {
       text: '关于我们',
       click: () => {
         yTRouter.router2AboutUS()
       },
-      src: $r('app.media.right_arrow')
+      src: $r('app.media.mine_right_arrow')
     }
   ]
 
@@ -53,65 +61,69 @@ export struct Mine {
   }
 
   build() {
-    Column() {
-      Row() {
-        Row() {
-          Image(this.userInfo.getHeadImg())
-            .aspectRatio(1)
-            .height(40)
-            .borderRadius(20)
-            .margin({ right: 9 })
+    RelativeContainer() {
+      Image(this.userInfo.getHeadImg())
+        .aspectRatio(1)
+        .height(80)
+        .borderRadius(999)
+        .border({ width: 4, color: Color.White })
 
-          Column({ space: 7 }) {
-            Text(this.userInfo.getName())
-              .fontSize(16)
-              .fontColor(Color.Black)
-            Text() {
-              Span('ID:' + this.userInfo.getId())
-              ImageSpan($r('app.media.copy'))
-                .width(7)
-                .height(8)
-                .margin({ left: 4 })
-                .onClick(() => {
-                  copyText((this.userInfo.getId()))
-                })
-                .offset({ bottom: 4 })
-            }
-            .fontColor('#80000000')
-            .fontSize($r('[basic].float.page_text_font_size_10'))
-          }
-          .alignItems(HorizontalAlign.Start)
-        }
-        .onClick(() => {
+        .alignRules({
+          top: { anchor: "__container__", align: VerticalAlign.Top },
+          left: { anchor: "__container__", align: HorizontalAlign.Start },
+          bottom: { anchor: "bottomColumn", align: VerticalAlign.Top },
+          bias: { vertical: 176 / (176 - 40) }
+        })
+        .offset({ x: 28 })
+        .zIndex(999)
+        .id("headerImg")
+      Text(this.userInfo.getName())
+        .fontSize(18)
+        .fontColor('#FF1C1C1C')
+        .fontWeight(500)
+        .alignRules({
+          top: { anchor: "headerImg", align: VerticalAlign.Bottom },
+          left: { anchor: "headerImg", align: HorizontalAlign.Start },
+        })
+        .offset({ x: 28, y: 20 })
+        .zIndex(999)
 
-          if (this.userInfo.checkLogin()) {
+
+      Text(this.userInfo.checkLogin() ? '编辑' : '登录')
+        .textAlign(TextAlign.Center)
+        .height(29)
+        .width(57)
+        .borderRadius(32)
+        .fontColor(Color.White)
+        .fontSize(14)
+        .fontWeight(400)
+        .alignRules({
+          center: { anchor: "headerImg", align: VerticalAlign.Bottom },
+          right: { anchor: "__container__", align: HorizontalAlign.End },
+        })
+        .zIndex(999)
+        .linearGradient({ angle: 135, colors: [['#CAE2F9', -0.1571], ['#D4D1F4', 0.4709], ['#EDF5FD', 1.1235]] })
+        .offset({ x: -32, y: -2 })
+        .onClick(() => {
+          if (!this.userInfo.checkLogin()) {
+            yTRouter.router2LoginPage()
+          } else {
             yTRouter.router2SettingPage()
-            return
           }
-          yTRouter.router2LoginPage()
         })
-      }
-      .width('100%')
-      .margin({ bottom: 30 })
-
-      // ShowBannerAd()
       Column() {
         List() {
-          ForEach(this.setArr, (item: BasicType<undefined>, index) => {
+          ForEach(this.setArr, (item: BasicType, index) => {
             ListItem() {
               Row() {
                 Text(item.text)
-                  .fontColor('#80000000')
-                  .fontSize(12)
+                  .fontColor('#FF1C1C1C')
+                  .fontSize(14)
                 if (!index) {
-                  Row() {
-                    Text(this.userInfo.getAiNum()?.toString() ?? '')
-                      .fontWeight(600)
-                      .fontSize($r('[basic].float.page_text_font_size_14'))
-                    Image($r('app.media.right_arrow'))
-                      .width(24)
-                      .aspectRatio(1)
-                  }
+                  Text('去分享')
+                    .fontColor('#801C1C1C')
+                    .fontSize(14)
+                    .fontWeight(400)
                 } else {
                   Image($r('app.media.right_arrow'))
                     .width(24)
@@ -119,7 +131,7 @@ export struct Mine {
                 }
               }
               .width('100%')
-              .height(36)
+              .height(56)
               .justifyContent(FlexAlign.SpaceBetween)
               .onClick(() => {
                 item.click?.()
@@ -127,17 +139,48 @@ export struct Mine {
             }
           })
         }
-        .padding({ left: 12, right: 4 })
-        .divider({ strokeWidth: 1, color: '#0A000000', endMargin: 8 })
-        .margin({ top: 30 })
+        .divider({ strokeWidth: 1, color: '#1A1C1C1C', })
         .width('100%')
         .height('100%')
       }
-      .layoutWeight(1)
+      .backgroundColor(Color.White)
       .width('100%')
+      .height(550)
+      .borderRadius({ topRight: 32 })
+      .alignRules({
+        bottom: { anchor: "__container__", align: VerticalAlign.Bottom },
+        left: { anchor: "__container__", align: HorizontalAlign.Start },
+      })
+      .id("bottomColumn")
+      .padding({ top: 142, left: 24, right: 24 })
 
     }
-    .padding({ top: this.safeTop + 22, left: 16, right: 16 })
     .height('100%')
+    .backgroundImage($r('app.media.mine_bgc'))
+    .backgroundImageSize({ width: '100%', height: 305 })
+    .backgroundImagePosition(Alignment.Top)
+  }
+
+  async shareData() {
+    try {
+      // 构造ShareData,需配置一条有效数据信息
+      const data = new systemShare.SharedData({
+        // utd: uniformTypeDescriptor.UniformDataType.HYPERLINK,
+        utd: uniformTypeDescriptor.UniformDataType.TEXT,
+        title: '盒小仓',
+        content: 'http://appgallery.huawei.com/app/detail?id=6917580461832049757',
+        description: "http://appgallery.huawei.com/app/detail?id=6917580461832049757"
+      })
+      const controller = new systemShare.ShareController(data)
+      const context = this.getUIContext().getHostContext()! as common.UIAbilityContext;
+      // 进行分享面板显示
+      controller.show(context, {
+        previewMode: systemShare.SharePreviewMode.DEFAULT,
+        selectionMode: systemShare.SelectionMode.SINGLE,
+        // anchor: { windowOffset: { x: 0, y: 0 }, size: { width: this.breakWidth, height: 500 } }
+      })
+    } catch (error) {
+      IBestToast.show({ message: '当前设备不支持', duration: 500 })
+    }
   }
 }

BIN
features/user/src/main/resources/base/media/mine_bgc.png


+ 3 - 0
features/user/src/main/resources/base/media/mine_right_arrow.svg

@@ -0,0 +1,3 @@
+<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="design-iconfont">
+  <path d="M9 6L14.5 11L9 17.5" stroke="#C7C7CC" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
+</svg>

+ 1 - 1
products/entry/src/main/ets/entryability/EntryAbility.ets

@@ -56,7 +56,7 @@ export default class EntryAbility extends UIAbility {
         })
       permissionController.init(this.context)
         .then(() => {
-          permissionController.askPermission(["ohos.permission.APP_TRACKING_CONSENT"], (res, err) => {
+          permissionController.askPermissions(["ohos.permission.APP_TRACKING_CONSENT"], (res, err) => {
             if (err) {
               YTLog.error(err)
             } else {