Explorar el Código

Merge branch 'base' into tabbar

feige996 hace 10 meses
padre
commit
c1b12eab84

+ 5 - 4
package.json

@@ -1,7 +1,7 @@
 {
   "name": "unibest",
   "type": "commonjs",
-  "version": "2.12.2",
+  "version": "2.13.0",
   "description": "unibest - 最好的 uniapp 开发模板",
   "update-time": "2025-06-17",
   "author": {
@@ -11,14 +11,15 @@
     "github": "https://github.com/feige996",
     "gitee": "https://gitee.com/feige996"
   },
+  "homepage": "https://unibest.tech",
   "license": "MIT",
   "repository": "https://github.com/feige996/unibest",
   "repository-gitee": "https://gitee.com/feige996/unibest",
-  "repository-deprecated": "https://github.com/codercup/unibest",
+  "repository-old": "https://github.com/codercup/unibest",
   "bugs": {
-    "url": "https://github.com/feige996/unibest/issues"
+    "url": "https://github.com/feige996/unibest/issues",
+    "url-old": "https://github.com/codercup/unibest/issues"
   },
-  "homepage": "https://feige996.github.io/unibest/",
   "engines": {
     "node": ">=18",
     "pnpm": ">=7.30"

+ 6 - 6
pages.config.ts

@@ -48,12 +48,12 @@ export default defineUniPages({
       //   icon: '/static/logo.svg',
       //   iconType: 'local',
       // },
-      {
-        pagePath: 'pages/mine/index',
-        text: '我的',
-        icon: 'iconfont icon-my',
-        iconType: 'iconfont',
-      },
+      // {
+      //   pagePath: 'pages/mine/index',
+      //   text: '我的',
+      //   icon: 'iconfont icon-my',
+      //   iconType: 'iconfont',
+      // },
     ],
   },
 })

+ 0 - 47
src/components/privacy-popup/index.scss

@@ -1,47 +0,0 @@
-@import 'wot-design-uni/components/wd-button/index.scss';
-:deep(.wd-privacy-popup) {
-  width: 600rpx;
-  padding: 0 24rpx;
-  box-sizing: border-box;
-  border-radius: 32rpx;
-  overflow: hidden;
-}
-
-.wd-privacy-popup {
-  &__header {
-    width: 100%;
-    height: 128rpx;
-    line-height: 128rpx;
-    color: rgba(0, 0, 0, 0.85);
-    font-size: 30rpx;
-    padding: 0 12rpx;
-    box-sizing: border-box;
-  }
-
-  &__container {
-    width: 100%;
-    box-sizing: border-box;
-    padding: 0 12rpx;
-    margin-bottom: 32rpx;
-
-    font-size: 28rpx;
-    line-height: 1.8;
-    color: #3e3e3e;
-    text-align: left;
-    font-weight: 550;
-    &-protocol {
-      color: #4d80f0;
-    }
-  }
-
-  &__footer {
-    display: flex;
-    justify-content: space-between;
-    padding-bottom: 36rpx;
-
-    button {
-      border: none;
-      outline: none;
-    }
-  }
-}

+ 0 - 144
src/components/privacy-popup/privacy-popup.vue

@@ -1,144 +0,0 @@
-<template>
-  <view>
-    <wd-popup
-      v-model="showPopup"
-      :close-on-click-modal="false"
-      custom-class="wd-privacy-popup"
-      @close="handleClose"
-    >
-      <view class="wd-privacy-popup__header">
-        <!--标题-->
-        <view class="wd-picker__title">{{ title }}</view>
-      </view>
-      <view class="wd-privacy-popup__container">
-        <text>{{ desc }}</text>
-        <text class="wd-privacy-popup__container-protocol" @click="openPrivacyContract">
-          {{ protocol }}
-        </text>
-        <text>{{ subDesc }}</text>
-      </view>
-      <view class="wd-privacy-popup__footer">
-        <button
-          class="wd-privacy-popup__footer-disagree wd-button is-block is-round is-medium is-plain"
-          id="disagree-btn"
-          @click="handleDisagree"
-        >
-          拒绝
-        </button>
-        <button
-          class="wd-privacy-popup__footer-agree wd-button is-primary is-block is-round is-medium"
-          id="agree-btn"
-          open-type="agreePrivacyAuthorization"
-          @agreeprivacyauthorization="handleAgree"
-        >
-          同意
-        </button>
-      </view>
-    </wd-popup>
-  </view>
-</template>
-
-<script lang="ts">
-export default {
-  name: 'privacy-popup',
-  options: {
-    virtualHost: true,
-    addGlobalClass: true,
-    styleIsolation: 'shared',
-  },
-}
-</script>
-
-<script lang="ts" setup>
-import { onBeforeMount, ref } from 'vue'
-
-type Props = {
-  title?: string // 标题
-  desc?: string // 描述
-  subDesc?: string // 字描述
-  protocol?: string // 协议名称
-}
-
-const props = withDefaults(defineProps<Props>(), {
-  title: '用户隐私保护提示',
-  desc: '感谢您使用本应用,您使用本应用的服务之前请仔细阅读并同意',
-  subDesc:
-    '。当您点击同意并开始时用产品服务时,即表示你已理解并同息该条款内容,该条款将对您产生法律约束力。如您拒绝,将无法使用相应服务。',
-  protocol: '《用户隐私保护指引》',
-})
-
-const showPopup = ref<boolean>(false) // 是否展示popup
-
-const privacyResolves = ref(new Set()) // onNeedPrivacyAuthorization的reslove
-
-const privacyHandler = (resolve: any) => {
-  showPopup.value = true
-  privacyResolves.value.add(resolve)
-}
-
-const emit = defineEmits(['agree', 'disagree'])
-
-onBeforeMount(() => {
-  // 注册监听
-  if ((wx as any).onNeedPrivacyAuthorization) {
-    ;(wx as any).onNeedPrivacyAuthorization((resolve: any) => {
-      if (typeof privacyHandler === 'function') {
-        privacyHandler(resolve)
-      }
-    })
-  }
-})
-
-/**
- * 同意隐私协议
- */
-function handleAgree() {
-  showPopup.value = false
-  privacyResolves.value.forEach((resolve: any) => {
-    resolve({
-      event: 'agree',
-      buttonId: 'agree-btn',
-    })
-  })
-  privacyResolves.value.clear()
-  emit('agree')
-}
-
-/**
- * 拒绝隐私协议
- */
-function handleDisagree() {
-  showPopup.value = false
-  privacyResolves.value.forEach((resolve: any) => {
-    resolve({
-      event: 'disagree',
-    })
-  })
-  privacyResolves.value.clear()
-}
-
-/**
- * 打开隐私协议
- */
-function openPrivacyContract() {
-  ;(wx as any).openPrivacyContract({
-    success: (res) => {
-      console.log('openPrivacyContract success')
-    },
-    fail: (res) => {
-      console.error('openPrivacyContract fail', res)
-    },
-  })
-}
-
-/**
- * 弹出框关闭时清空
- */
-function handleClose() {
-  privacyResolves.value.clear()
-}
-</script>
-
-<style lang="scss" scoped>
-@import './index.scss';
-</style>

+ 0 - 584
src/pages/login/index.vue

@@ -1,584 +0,0 @@
-<route lang="json5" type="page">
-{
-  style: {
-    navigationBarTitleText: '登录',
-    navigationStyle: 'custom',
-  },
-}
-</route>
-<template>
-  <view class="login-container">
-    <!-- 背景装饰元素 -->
-    <view class="bg-decoration bg-circle-1"></view>
-    <view class="bg-decoration bg-circle-2"></view>
-    <view class="bg-decoration bg-circle-3"></view>
-
-    <view class="login-header">
-      <image class="login-logo" :src="appLogo" mode="aspectFit"></image>
-      <view class="login-title">{{ appTitle }}</view>
-    </view>
-    <view class="login-form">
-      <view class="welcome-text">欢迎登录</view>
-      <view class="login-desc">请输入您的账号和密码</view>
-      <view class="login-input-group">
-        <view class="input-wrapper">
-          <wd-input
-            v-model="loginForm.username"
-            prefix-icon="user"
-            placeholder="请输入用户名"
-            clearable
-            class="login-input"
-            :border="false"
-            required
-          ></wd-input>
-          <view class="input-bottom-line"></view>
-        </view>
-        <view class="input-wrapper">
-          <wd-input
-            v-model="loginForm.password"
-            prefix-icon="lock-on"
-            placeholder="请输入密码"
-            clearable
-            show-password
-            class="login-input"
-            :border="false"
-            required
-          ></wd-input>
-          <view class="input-bottom-line"></view>
-        </view>
-        <!-- 验证码区域 -->
-        <view class="input-wrapper captcha-wrapper">
-          <wd-input
-            v-if="captcha.captchaEnabled"
-            v-model="loginForm.code"
-            prefix-icon="secured"
-            placeholder="请输入验证码"
-            clearable
-            class="login-input captcha-input"
-            :border="false"
-            required
-          >
-            <template #suffix>
-              <image
-                class="captcha-image"
-                :src="'data:image/gif;base64,' + captcha.image"
-                mode="aspectFit"
-                @click="refreshCaptcha"
-              ></image>
-            </template>
-          </wd-input>
-          <view class="input-bottom-line"></view>
-        </view>
-      </view>
-      <!-- 登录按钮组 -->
-      <view class="login-buttons">
-        <!-- 账号密码登录按钮 -->
-        <wd-button
-          type="primary"
-          size="large"
-          block
-          @click="handleAccountLogin"
-          class="account-login-btn"
-        >
-          <wd-icon name="right" size="18px" class="login-icon"></wd-icon>
-          登录
-        </wd-button>
-        <!-- 微信小程序一键登录按钮 -->
-        <!-- #ifdef MP-WEIXIN -->
-        <view class="divider">
-          <view class="divider-line"></view>
-          <view class="divider-text">或</view>
-          <view class="divider-line"></view>
-        </view>
-        <wd-button
-          type="info"
-          size="large"
-          block
-          plain
-          @click="handleWechatLogin"
-          class="wechat-login-btn"
-        >
-          微信一键登录
-        </wd-button>
-        <!-- #endif -->
-      </view>
-    </view>
-    <!-- 隐私协议勾选 -->
-    <view class="privacy-agreement">
-      <wd-checkbox
-        v-model="agreePrivacy"
-        shape="square"
-        class="privacy-checkbox"
-        active-color="var(--wot-color-theme, #1989fa)"
-      >
-        <view class="agreement-text">
-          我已阅读并同意
-          <text class="agreement-link" @click.stop="handleAgreement('user')">《用户协议》</text>
-          和
-          <text class="agreement-link" @click.stop="handleAgreement('privacy')">《隐私政策》</text>
-        </view>
-      </wd-checkbox>
-    </view>
-    <view class="login-footer"></view>
-  </view>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import { useUserStore } from '@/store/user'
-import { isMpWeixin } from '@/utils/platform'
-import { getCode, ILoginForm } from '@/api/login'
-import { toast } from '@/utils/toast'
-import { isTableBar } from '@/utils/index'
-import { ICaptcha } from '@/api/login.typings'
-const redirectRoute = ref('')
-
-// 获取环境变量
-const appTitle = ref(import.meta.env.VITE_APP_TITLE || 'Unibest Login')
-const appLogo = ref(import.meta.env.VITE_APP_LOGO || '/static/logo.svg')
-
-// 初始化store
-const userStore = useUserStore()
-// 路由位置
-// 验证码图片
-const captcha = ref<ICaptcha>({
-  captchaEnabled: false,
-  uuid: '',
-  image: '',
-})
-// 登录表单数据
-const loginForm = ref<ILoginForm>({
-  username: 'admin',
-  password: '123456',
-  code: '',
-  uuid: '',
-})
-// 隐私协议勾选状态
-const agreePrivacy = ref(true)
-
-// 页面加载完毕时触发
-onLoad((option) => {
-  // 一进来就刷新验证码
-  captcha.value.captchaEnabled && refreshCaptcha()
-  // 获取跳转路由
-  if (option.redirect) {
-    redirectRoute.value = option.redirect
-  }
-})
-
-// 账号密码登录
-const handleAccountLogin = async () => {
-  if (!agreePrivacy.value) {
-    toast.error('请阅读同意协议')
-    return
-  }
-  // 表单验证
-  if (!loginForm.value.username) {
-    toast.error('请输入用户名')
-    return
-  }
-  if (!loginForm.value.password) {
-    toast.error('请输入密码')
-    return
-  }
-  if (captcha.value.captchaEnabled && !loginForm.value.code) {
-    toast.error('请输入验证码')
-    return
-  }
-  // 执行登录
-  await userStore.login(loginForm.value)
-  // 跳转到首页或重定向页面
-  const targetUrl = redirectRoute.value || '/pages/index/index'
-  if (isTableBar(targetUrl)) {
-    uni.switchTab({ url: targetUrl })
-  } else {
-    uni.redirectTo({ url: targetUrl })
-  }
-}
-
-// 微信登录
-const handleWechatLogin = async () => {
-  if (!isMpWeixin) {
-    toast.info('请在微信小程序中使用此功能')
-    return
-  }
-
-  // 验证是否同意隐私协议
-  if (!agreePrivacy.value) {
-    toast.error('请先阅读并同意用户协议和隐私政策')
-    return
-  }
-  // 微信登录
-  await userStore.wxLogin()
-  // 跳转到首页或重定向页面
-  const targetUrl = redirectRoute.value || '/pages/index/index'
-  if (isTableBar(targetUrl)) {
-    uni.switchTab({ url: targetUrl })
-  } else {
-    uni.redirectTo({ url: targetUrl })
-  }
-}
-
-// 刷新验证码
-const refreshCaptcha = () => {
-  // 获取验证码
-  getCode().then((res) => {
-    const { data } = res
-    loginForm.value.uuid = data.uuid
-    captcha.value = data
-  })
-}
-
-// 处理协议点击
-const handleAgreement = (type: 'user' | 'privacy') => {
-  const title = type === 'user' ? '用户协议' : '隐私政策'
-  // showToast(`查看${title}`)
-  // 实际项目中可以跳转到对应的协议页面
-  // uni.navigateTo({
-  //   url: `/pages/agreement/${type}`
-  // })
-}
-</script>
-
-<style lang="scss" scoped>
-/* 验证码输入框样式 */
-.captcha-wrapper {
-  .captcha-input {
-    :deep(.wd-input__suffix) {
-      margin-right: 0;
-      padding-right: 0;
-    }
-  }
-
-  .captcha-image {
-    width: 100px;
-    height: 36px;
-    margin-left: 10px;
-    border-radius: 8px;
-    cursor: pointer;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    transition: all 0.3s ease;
-    position: relative;
-    overflow: hidden;
-
-    &::after {
-      content: '';
-      position: absolute;
-      top: 0;
-      left: 0;
-      right: 0;
-      bottom: 0;
-      background: linear-gradient(to bottom, rgba(255, 255, 255, 0.1), transparent);
-      pointer-events: none;
-    }
-
-    &:active {
-      opacity: 0.8;
-      transform: scale(0.96);
-      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
-    }
-  }
-}
-
-.login-container {
-  box-sizing: border-box;
-  display: flex;
-  flex-direction: column;
-  min-height: 100vh;
-  padding: 0 70rpx;
-  background-color: #ffffff;
-  background-image: linear-gradient(
-    135deg,
-    rgba(25, 137, 250, 0.05) 0%,
-    rgba(255, 255, 255, 0) 100%
-  );
-  position: relative;
-  overflow: hidden;
-}
-
-/* 背景装饰元素 */
-.bg-decoration {
-  position: absolute;
-  border-radius: 50%;
-  background: linear-gradient(135deg, rgba(25, 137, 250, 0.05), rgba(25, 137, 250, 0.1));
-  z-index: 0;
-  pointer-events: none;
-}
-
-.bg-circle-1 {
-  width: 500rpx;
-  height: 500rpx;
-  top: -200rpx;
-  right: -200rpx;
-  opacity: 0.6;
-}
-
-.bg-circle-2 {
-  width: 400rpx;
-  height: 400rpx;
-  bottom: 10%;
-  left: -200rpx;
-  opacity: 0.4;
-}
-
-.bg-circle-3 {
-  width: 300rpx;
-  height: 300rpx;
-  bottom: -100rpx;
-  right: 10%;
-  opacity: 0.3;
-  background: linear-gradient(135deg, rgba(7, 193, 96, 0.05), rgba(7, 193, 96, 0.1));
-}
-
-.login-header {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  margin-top: 120rpx;
-  animation: fadeInDown 0.8s ease-out;
-
-  .login-logo {
-    width: 200rpx;
-    height: 200rpx;
-    border-radius: 36rpx;
-    box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.12);
-    transition: all 0.3s ease;
-
-    &:active {
-      transform: scale(0.95);
-      box-shadow: 0 6rpx 15rpx rgba(0, 0, 0, 0.1);
-    }
-  }
-
-  .login-title {
-    margin-top: 30rpx;
-    font-size: 46rpx;
-    font-weight: bold;
-    color: #333333;
-    letter-spacing: 3rpx;
-    text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
-  }
-}
-
-.login-form {
-  flex: 1;
-  margin-top: 70rpx;
-  animation: fadeIn 0.8s ease-out 0.2s both;
-
-  .welcome-text {
-    margin-bottom: 16rpx;
-    font-size: 48rpx;
-    font-weight: bold;
-    color: #333333;
-    text-align: center;
-    letter-spacing: 1rpx;
-  }
-
-  .login-desc {
-    margin-bottom: 70rpx;
-    font-size: 28rpx;
-    color: #888888;
-    text-align: center;
-  }
-
-  .login-input-group {
-    margin-bottom: 60rpx;
-    position: relative;
-    z-index: 1;
-
-    .input-wrapper {
-      position: relative;
-      margin-bottom: 50rpx;
-      transition: all 0.3s ease;
-      border-radius: 16rpx;
-      overflow: hidden;
-
-      &:last-child {
-        margin-bottom: 0;
-      }
-
-      .login-input {
-        padding: 12rpx 20rpx;
-        background-color: rgba(245, 247, 250, 0.7);
-        border-radius: 16rpx;
-        transition: all 0.3s ease;
-
-        :deep(.wd-input__inner) {
-          font-size: 30rpx;
-          color: #333333;
-        }
-
-        :deep(.wd-input__placeholder) {
-          font-size: 28rpx;
-          color: #aaaaaa;
-        }
-
-        &:focus-within {
-          background-color: rgba(245, 247, 250, 0.95);
-          box-shadow: 0 6rpx 16rpx rgba(0, 0, 0, 0.06);
-          transform: translateY(-3rpx);
-        }
-      }
-
-      .input-bottom-line {
-        position: absolute;
-        bottom: -2rpx;
-        left: 5%;
-        width: 90%;
-        height: 2rpx;
-        background: linear-gradient(
-          to right,
-          transparent,
-          var(--wot-color-theme, #1989fa),
-          transparent
-        );
-        transition: transform 0.4s ease;
-        transform: scaleX(0);
-        opacity: 0.8;
-      }
-
-      &:focus-within .input-bottom-line {
-        transform: scaleX(1);
-      }
-
-      .input-icon {
-        margin-right: 16rpx;
-        color: #666666;
-        transition: color 0.3s ease;
-      }
-
-      &:focus-within .input-icon {
-        color: var(--wot-color-theme, #1989fa);
-      }
-    }
-  }
-
-  .login-buttons {
-    display: flex;
-    flex-direction: column;
-    gap: 36rpx;
-
-    .account-login-btn {
-      height: 96rpx;
-      margin-top: 20rpx;
-      font-size: 32rpx;
-      font-weight: 500;
-      letter-spacing: 2rpx;
-      border-radius: 48rpx;
-      box-shadow: 0 10rpx 20rpx rgba(25, 137, 250, 0.25);
-      transition: all 0.3s ease;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-
-      .login-icon {
-        margin-right: 8rpx;
-        opacity: 0.8;
-        transition: all 0.3s ease;
-      }
-
-      &:active {
-        box-shadow: 0 5rpx 10rpx rgba(25, 137, 250, 0.2);
-        transform: scale(0.98);
-
-        .login-icon {
-          transform: translateX(3rpx);
-        }
-      }
-    }
-
-    .divider {
-      display: flex;
-      align-items: center;
-      margin: 24rpx 0;
-
-      .divider-line {
-        flex: 1;
-        height: 1px;
-        background-color: #eeeeee;
-      }
-
-      .divider-text {
-        padding: 0 24rpx;
-        font-size: 24rpx;
-        color: #999999;
-      }
-    }
-
-    .wechat-login-btn {
-      height: 96rpx;
-      font-size: 32rpx;
-      color: #07c160;
-      border-color: #07c160;
-      border-radius: 48rpx;
-      transition: all 0.3s ease;
-
-      .wechat-icon {
-        margin-right: 12rpx;
-      }
-
-      &:active {
-        background-color: rgba(7, 193, 96, 0.08);
-        transform: scale(0.98);
-      }
-    }
-  }
-}
-
-.privacy-agreement {
-  display: flex;
-  justify-content: center;
-  margin: 30rpx 0 40rpx;
-  animation: fadeIn 0.8s ease-out 0.4s both;
-
-  .privacy-checkbox {
-    display: flex;
-    align-items: center;
-  }
-
-  .agreement-text {
-    font-size: 26rpx;
-    line-height: 1.6;
-    color: #666666;
-
-    .agreement-link {
-      padding: 0 4rpx;
-      font-weight: 500;
-      color: var(--wot-color-theme, #1989fa);
-      transition: all 0.3s ease;
-
-      &:active {
-        opacity: 0.8;
-        transform: scale(0.98);
-      }
-    }
-  }
-}
-
-.login-footer {
-  padding: 50rpx 0;
-  margin-top: auto;
-}
-
-/* 添加动画效果 */
-@keyframes fadeIn {
-  from {
-    opacity: 0;
-  }
-  to {
-    opacity: 1;
-  }
-}
-
-@keyframes fadeInDown {
-  from {
-    opacity: 0;
-    transform: translateY(-20px);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-</style>

+ 0 - 173
src/pages/mine/about/index.vue

@@ -1,173 +0,0 @@
-<route lang="json5">
-{
-  style: {
-    navigationBarTitleText: '关于我们',
-  },
-}
-</route>
-
-<template>
-  <view class="about-container">
-    <view class="about-card">
-      <!-- 应用信息 -->
-      <view class="app-info">
-        <view class="logo-wrapper">
-          <wd-img :src="appLogo" width="120px" height="120px" radius="24rpx"></wd-img>
-        </view>
-        <view class="app-name">{{ appTitle }}</view>
-        <view class="app-version">版本 {{ packageJson.version }}</view>
-      </view>
-
-      <!-- 联系方式 -->
-      <view class="info-section">
-        <view class="section-title">联系我们</view>
-        <view class="section-content">
-          <view class="contact-item">
-            <wd-icon name="phone" size="20px" class="contact-icon"></wd-icon>
-            <text class="contact-text">客服电话:400-XXX-XXXX</text>
-          </view>
-          <view class="contact-item">
-            <wd-icon name="mail" size="20px" class="contact-icon"></wd-icon>
-            <text class="contact-text">邮箱:support@unibest.tech</text>
-          </view>
-          <view class="contact-item">
-            <wd-icon name="location" size="20px" class="contact-icon"></wd-icon>
-            <text class="contact-text">地址:中国·深圳</text>
-          </view>
-        </view>
-      </view>
-
-      <!-- 版权信息 -->
-      <view class="copyright">
-        <text>Copyright © 2025-{{ currentYear }} {{ appTitle }}</text>
-        <text>All Rights Reserved</text>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { ref, computed } from 'vue'
-import packageJson from '@/../package.json'
-
-const appTitle = ref(import.meta.env.VITE_APP_TITLE || 'unibest')
-const appLogo = ref(import.meta.env.VITE_APP_LOGO || '/static/logo.svg')
-
-// 当前年份
-const currentYear = computed(() => new Date().getFullYear())
-</script>
-
-<style lang="scss" scoped>
-.about-container {
-  background-color: #f5f7fa;
-  padding: 30rpx;
-}
-
-.about-card {
-  background-color: #ffffff;
-  border-radius: 24rpx;
-  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
-  overflow: hidden;
-  padding: 40rpx 30rpx;
-}
-
-/* 应用信息 */
-.app-info {
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  padding: 30rpx 0 50rpx;
-  border-bottom: 2rpx solid #f0f0f0;
-}
-
-.logo-wrapper {
-  margin-bottom: 20rpx;
-  box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.08);
-  border-radius: 24rpx;
-}
-
-.app-name {
-  font-size: 40rpx;
-  font-weight: 600;
-  color: #333;
-  margin-bottom: 10rpx;
-}
-
-.app-version {
-  font-size: 28rpx;
-  color: #999;
-}
-
-/* 信息区块 */
-.info-section {
-  padding: 40rpx 0;
-  border-bottom: 2rpx solid #f0f0f0;
-}
-
-.section-title {
-  font-size: 34rpx;
-  font-weight: 600;
-  color: #333;
-  margin-bottom: 20rpx;
-  position: relative;
-  padding-left: 24rpx;
-
-  &::before {
-    content: '';
-    position: absolute;
-    left: 0;
-    top: 50%;
-    transform: translateY(-50%);
-    width: 8rpx;
-    height: 32rpx;
-    background: linear-gradient(135deg, #4a7bff, #6a5acd);
-    border-radius: 4rpx;
-  }
-}
-
-.section-content {
-  padding: 0 10rpx;
-}
-
-.content-text {
-  font-size: 30rpx;
-  color: #666;
-  line-height: 1.6;
-  text-align: justify;
-}
-
-/* 联系方式 */
-.contact-item {
-  display: flex;
-  align-items: center;
-  margin-bottom: 20rpx;
-
-  &:last-child {
-    margin-bottom: 0;
-  }
-}
-
-.contact-icon {
-  margin-right: 20rpx;
-  color: #4a7bff;
-}
-
-.contact-text {
-  font-size: 30rpx;
-  color: #666;
-}
-
-/* 版权信息 */
-.copyright {
-  padding-top: 40rpx;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-
-  text {
-    font-size: 26rpx;
-    color: #999;
-    line-height: 1.6;
-  }
-}
-</style>

+ 0 - 375
src/pages/mine/index.vue

@@ -1,375 +0,0 @@
-<route lang="json5">
-{
-  layout: 'tabbar',
-  style: {
-    navigationBarTitleText: '我的',
-  },
-}
-</route>
-
-<template>
-  <view class="profile-container">
-    {{ JSON.stringify(userInfo) }}
-    <!-- 用户信息区域 -->
-    <view class="user-info-section">
-      <!-- #ifdef MP-WEIXIN -->
-      <button class="avatar-button" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
-        <wd-img :src="userInfo.avatar" width="80px" height="80px" radius="50%"></wd-img>
-      </button>
-      <!-- #endif -->
-      <!-- #ifndef MP-WEIXIN -->
-      <view class="avatar-wrapper" @click="run">
-        <wd-img :src="userInfo.avatar" width="100%" height="100%" radius="50%"></wd-img>
-      </view>
-      <!-- #endif -->
-      <view class="user-details">
-        <!-- #ifdef MP-WEIXIN -->
-        <input
-          type="nickname"
-          class="weui-input"
-          placeholder="请输入昵称"
-          v-model="userInfo.username"
-        />
-        <!-- #endif -->
-        <!-- #ifndef MP-WEIXIN -->
-        <view class="username">{{ userInfo.username }}</view>
-        <!-- #endif -->
-        <view class="user-id">ID: {{ userInfo.id }}</view>
-      </view>
-    </view>
-
-    <!-- 功能区块 -->
-    <view class="function-section">
-      <view class="cell-group">
-        <view class="group-title">账号管理</view>
-        <wd-cell title="个人资料" is-link @click="handleProfileInfo">
-          <template #icon>
-            <wd-icon name="user" size="20px"></wd-icon>
-          </template>
-        </wd-cell>
-        <wd-cell title="账号安全" is-link @click="handlePassword">
-          <template #icon>
-            <wd-icon name="lock-on" size="20px"></wd-icon>
-          </template>
-        </wd-cell>
-      </view>
-
-      <view class="cell-group">
-        <view class="group-title">通用设置</view>
-        <wd-cell title="消息通知" is-link @click="handleInform">
-          <template #icon>
-            <wd-icon name="notification" size="20px"></wd-icon>
-          </template>
-        </wd-cell>
-        <wd-cell title="清理缓存" is-link @click="handleClearCache">
-          <template #icon>
-            <wd-icon name="clear" size="20px"></wd-icon>
-          </template>
-        </wd-cell>
-        <wd-cell title="应用更新" is-link @click="handleAppUpdate">
-          <template #icon>
-            <wd-icon name="refresh1" size="20px"></wd-icon>
-          </template>
-        </wd-cell>
-        <wd-cell title="关于我们" is-link @click="handleAbout">
-          <template #icon>
-            <wd-icon name="info-circle" size="20px"></wd-icon>
-          </template>
-        </wd-cell>
-      </view>
-
-      <view class="logout-button-wrapper">
-        <wd-button type="error" v-if="hasLogin" block @click="handleLogout">退出登录</wd-button>
-        <wd-button type="primary" v-else block @click="handleLogin">登录</wd-button>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { useUserStore } from '@/store'
-import { useToast } from 'wot-design-uni'
-import { useUpload } from '@/utils/uploadFile'
-import { storeToRefs } from 'pinia'
-import { IUploadSuccessInfo } from '@/api/login.typings'
-
-const userStore = useUserStore()
-// 使用storeToRefs解构userInfo
-const { userInfo } = storeToRefs(userStore)
-const toast = useToast()
-const hasLogin = ref(false)
-
-onShow((options) => {
-  hasLogin.value = !!uni.getStorageSync('token')
-  console.log('个人中心onShow', hasLogin.value, options)
-
-  hasLogin.value && useUserStore().getUserInfo()
-})
-// #ifndef MP-WEIXIN
-// 上传头像
-const { run } = useUpload<IUploadSuccessInfo>(
-  import.meta.env.VITE_UPLOAD_BASEURL,
-  {},
-  {
-    onSuccess: (res) => {
-      console.log('h5头像上传成功', res)
-      useUserStore().setUserAvatar(res.url)
-    },
-  },
-)
-// #endif
-
-// 微信小程序下登录
-const handleLogin = async () => {
-  // #ifdef MP-WEIXIN
-
-  // 微信登录
-  await userStore.wxLogin()
-  hasLogin.value = true
-  // #endif
-  // #ifndef MP-WEIXIN
-  uni.navigateTo({ url: '/pages/login/index' })
-  // #endif
-}
-
-// #ifdef MP-WEIXIN
-
-// 微信小程序下选择头像事件
-const onChooseAvatar = (e: any) => {
-  console.log('选择头像', e.detail)
-  const { avatarUrl } = e.detail
-  const { run } = useUpload<IUploadSuccessInfo>(
-    import.meta.env.VITE_UPLOAD_BASEURL,
-    {},
-    {
-      onSuccess: (res) => {
-        console.log('wx头像上传成功', res)
-        useUserStore().setUserAvatar(res.url)
-      },
-    },
-    avatarUrl,
-  )
-  run()
-}
-// #endif
-// #ifdef MP-WEIXIN
-// 微信小程序下设置用户名
-const getUserInfo = (e: any) => {
-  console.log(e.detail)
-}
-// #endif
-
-// 个人资料
-const handleProfileInfo = () => {
-  uni.navigateTo({ url: `/pages/mine/info/index` })
-}
-// 账号安全
-const handlePassword = () => {
-  uni.navigateTo({ url: `/pages/mine/password/index` })
-}
-// 消息通知
-const handleInform = () => {
-  // uni.navigateTo({ url: `/pages/mine/inform/index` })
-  toast.show('功能开发中')
-}
-// 应用更新
-const handleAppUpdate = () => {
-  // #ifdef MP
-  // #ifndef MP-HARMONY
-  const updateManager = uni.getUpdateManager()
-  updateManager.onCheckForUpdate(function (res) {
-    // 请求完新版本信息的回调
-    // console.log(res.hasUpdate)
-    if (res.hasUpdate) {
-      toast.show('检测到新版本,正在下载中...')
-    } else {
-      toast.show('已是最新版本')
-    }
-  })
-  updateManager.onUpdateReady(function (res) {
-    uni.showModal({
-      title: '更新提示',
-      content: '新版本已经准备好,是否重启应用?',
-      success(res) {
-        if (res.confirm) {
-          // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
-          updateManager.applyUpdate()
-        }
-      },
-    })
-  })
-  updateManager.onUpdateFailed(function (res) {
-    // 新的版本下载失败
-    toast.error('新版本下载失败')
-  })
-  // #endif
-  // #endif
-
-  // #ifndef MP
-  toast.show('功能开发中')
-  // #endif
-}
-// 关于我们
-const handleAbout = () => {
-  uni.navigateTo({ url: `/pages/mine/about/index` })
-}
-// 清除缓存
-const handleClearCache = () => {
-  uni.showModal({
-    title: '清除缓存',
-    content: '确定要清除所有缓存吗?\n清除后需要重新登录',
-    success: (res) => {
-      if (res.confirm) {
-        try {
-          // 清除所有缓存
-          uni.clearStorageSync()
-          // 清除用户信息并跳转到登录页
-          useUserStore().logout()
-          toast.show('清除缓存成功')
-        } catch (err) {
-          console.error('清除缓存失败:', err)
-          toast.error('清除缓存失败')
-        }
-      }
-    },
-  })
-}
-// 退出登录
-const handleLogout = () => {
-  uni.showModal({
-    title: '提示',
-    content: '确定要退出登录吗?',
-    success: (res) => {
-      if (res.confirm) {
-        // 清空用户信息
-        useUserStore().logout()
-        hasLogin.value = false
-        // 执行退出登录逻辑
-        toast.show('退出登录成功')
-        // #ifdef MP-WEIXIN
-        // 微信小程序,去首页
-        // uni.reLaunch({ url: '/pages/index/index' })
-        // #endif
-        // #ifndef MP-WEIXIN
-        // 非微信小程序,去登录页
-        // uni.reLaunch({ url: '/pages/login/index' })
-        // #endif
-      }
-    },
-  })
-}
-</script>
-
-<style lang="scss" scoped>
-/* 基础样式 */
-.profile-container {
-  overflow: hidden;
-  font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
-  background-color: #f7f8fa;
-}
-/* 用户信息区域 */
-.user-info-section {
-  display: flex;
-  align-items: center;
-  padding: 40rpx;
-  margin: 30rpx 30rpx 20rpx;
-  background-color: #fff;
-  border-radius: 24rpx;
-  box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.08);
-  transition: all 0.3s ease;
-}
-
-.avatar-wrapper {
-  width: 160rpx;
-  height: 160rpx;
-  margin-right: 40rpx;
-  overflow: hidden;
-  border: 4rpx solid #f5f5f5;
-  border-radius: 50%;
-  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
-}
-.avatar-button {
-  height: 160rpx;
-  padding: 0;
-  margin-right: 40rpx;
-  overflow: hidden;
-  border: 4rpx solid #f5f5f5;
-  border-radius: 50%;
-  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
-}
-.user-details {
-  flex: 1;
-}
-
-.username {
-  margin-bottom: 12rpx;
-  font-size: 38rpx;
-  font-weight: 600;
-  color: #333;
-  letter-spacing: 0.5rpx;
-}
-
-.user-id {
-  font-size: 28rpx;
-  color: #666;
-}
-
-.user-created {
-  margin-top: 8rpx;
-  font-size: 24rpx;
-  color: #999;
-}
-/* 功能区块 */
-.function-section {
-  padding: 0 20rpx;
-  margin-top: 20rpx;
-}
-
-.cell-group {
-  margin-bottom: 20rpx;
-  overflow: hidden;
-  background-color: #fff;
-  border-radius: 16rpx;
-  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
-}
-
-.group-title {
-  padding: 24rpx 30rpx 16rpx;
-  font-size: 30rpx;
-  font-weight: 500;
-  color: #999;
-  background-color: #fafafa;
-}
-
-:deep(.wd-cell) {
-  border-bottom: 1rpx solid #f5f5f5;
-
-  &:last-child {
-    border-bottom: none;
-  }
-
-  .wd-cell__title {
-    margin-left: 5px;
-    font-size: 32rpx;
-    color: #333;
-  }
-
-  .cell-icon {
-    margin-right: 20rpx;
-    font-size: 36rpx;
-  }
-}
-/* 退出登录按钮 */
-.logout-button-wrapper {
-  padding: 40rpx 30rpx;
-}
-
-:deep(.wd-button--danger) {
-  height: 88rpx;
-  font-size: 32rpx;
-  line-height: 88rpx;
-  color: #fff;
-  background-color: #f53f3f;
-  border-radius: 44rpx;
-}
-</style>

+ 0 - 190
src/pages/mine/info/index.vue

@@ -1,190 +0,0 @@
-<route lang="json5">
-{
-  style: {
-    navigationBarTitleText: '个人资料',
-  },
-}
-</route>
-
-<template>
-  <view class="profile-info-container">
-    <view class="profile-card">
-      <view class="form-wrapper">
-        <wd-form ref="formRef" :model="formData" label-width="160rpx" class="profile-form">
-          <wd-cell-group class="form-group">
-            <!-- 昵称 -->
-            <view class="sex-field">
-              <text class="field-label">昵称</text>
-              <wd-input
-                prop="name"
-                clearable
-                v-model="formData.name"
-                placeholder="请输入昵称"
-                :rules="[{ required: true, message: '请填写昵称' }]"
-                class="form-input"
-              />
-            </view>
-
-            <!-- 性别 -->
-            <view class="sex-field">
-              <text class="field-label">性别</text>
-              <wd-radio-group
-                v-model="formData.sex"
-                shape="button"
-                :rules="[{ required: true, message: '请选择性别' }]"
-              >
-                <wd-radio :value="'1'">男</wd-radio>
-                <wd-radio :value="'0'">女</wd-radio>
-              </wd-radio-group>
-            </view>
-          </wd-cell-group>
-        </wd-form>
-
-        <!-- 操作按钮 -->
-        <view class="form-actions">
-          <wd-button type="primary" size="large" @click="handleSubmit">保存修改</wd-button>
-        </view>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { ref } from 'vue'
-import { useUserStore } from '@/store'
-import { storeToRefs } from 'pinia'
-import { toast } from '@/utils/toast'
-import { updateInfo } from '@/api/login'
-
-// 表单引用
-const formRef = ref()
-
-// 用户信息
-const userStore = useUserStore()
-const { userInfo } = storeToRefs(userStore)
-
-// 表单数据
-const formData = ref({
-  id: userInfo.value.id,
-  name: userInfo.value.name,
-  sex: userInfo.value.sex,
-})
-
-// 提交表单
-const handleSubmit = async () => {
-  // 表单验证
-  const valid = await formRef.value.validate()
-  if (!valid) return
-  const { message } = await updateInfo(formData.value)
-  await useUserStore().getUserInfo()
-  toast.success(message)
-}
-</script>
-
-<style lang="scss" scoped>
-.profile-info-container {
-  min-height: 100vh;
-  background-color: #f5f7fa;
-  padding: 30rpx;
-}
-
-.profile-card {
-  background-color: #ffffff;
-  border-radius: 24rpx;
-  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
-  overflow: hidden;
-}
-
-.card-header {
-  padding: 40rpx 30rpx 20rpx;
-  border-bottom: 2rpx solid #f0f0f0;
-}
-
-.card-title {
-  font-size: 36rpx;
-  font-weight: 600;
-  color: #333;
-  position: relative;
-  display: inline-block;
-  padding-bottom: 16rpx;
-
-  &::after {
-    content: '';
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    width: 60rpx;
-    height: 6rpx;
-    background: linear-gradient(90deg, #4a7bff, #6a5acd);
-    border-radius: 6rpx;
-  }
-}
-
-.form-wrapper {
-  padding: 30rpx;
-}
-
-.form-group {
-  border-radius: 16rpx;
-  overflow: hidden;
-  margin-bottom: 40rpx;
-}
-
-.form-input {
-  font-size: 30rpx;
-}
-
-.sex-field {
-  display: flex;
-  align-items: center;
-  padding: 24rpx 30rpx;
-  background-color: #ffffff;
-}
-
-.field-label {
-  width: 160rpx;
-  font-size: 30rpx;
-  color: #333;
-}
-
-.radio-group {
-  flex: 1;
-  display: flex;
-  gap: 20rpx;
-}
-
-.radio-btn {
-  flex: 1;
-  height: 80rpx;
-  line-height: 80rpx;
-  text-align: center;
-  font-size: 30rpx;
-  border-radius: 12rpx;
-  background-color: #f5f7fa;
-
-  &:active {
-    opacity: 0.8;
-  }
-}
-
-.form-actions {
-  display: flex;
-  flex-direction: row;
-  gap: 20rpx;
-}
-
-.submit-btn {
-  height: 90rpx;
-  border-radius: 45rpx;
-  font-size: 32rpx;
-  font-weight: 500;
-  background: linear-gradient(135deg, #4a7bff, #6a5acd);
-  box-shadow: 0 8rpx 16rpx rgba(74, 123, 255, 0.2);
-  transition: all 0.3s ease;
-
-  &:active {
-    transform: translateY(2rpx);
-    box-shadow: 0 4rpx 8rpx rgba(74, 123, 255, 0.15);
-  }
-}
-</style>

+ 0 - 203
src/pages/mine/password/index.vue

@@ -1,203 +0,0 @@
-<route lang="json5">
-{
-  style: {
-    navigationBarTitleText: '修改密码',
-  },
-}
-</route>
-
-<template>
-  <view class="profile-info-container">
-    <view class="profile-card">
-      <view class="form-wrapper">
-        <wd-form ref="formRef" :model="formData" label-width="160rpx" class="profile-form">
-          <wd-cell-group class="form-group">
-            <!-- 昵称 -->
-            <view class="sex-field">
-              <text class="field-label">旧密码</text>
-              <wd-input
-                prop="oldPassword"
-                clearable
-                v-model="formData.oldPassword"
-                placeholder="请输入旧密码"
-                show-password
-                :rules="[{ required: true, message: '请填写旧密码' }]"
-                class="form-input"
-              />
-            </view>
-            <view class="sex-field">
-              <text class="field-label">新密码</text>
-              <wd-input
-                prop="newPassword"
-                clearable
-                v-model="formData.newPassword"
-                placeholder="请输入新密码"
-                show-password
-                :rules="[{ required: true, message: '请填写新密码' }]"
-                class="form-input"
-              />
-            </view>
-            <view class="sex-field">
-              <text class="field-label">确认密码</text>
-              <wd-input
-                prop="confirmPassword"
-                clearable
-                v-model="formData.confirmPassword"
-                placeholder="请输入新密码"
-                show-password
-                :rules="[{ required: true, message: '请填写新密码' }]"
-                class="form-input"
-              />
-            </view>
-          </wd-cell-group>
-        </wd-form>
-
-        <!-- 操作按钮 -->
-        <view class="form-actions">
-          <wd-button type="primary" size="large" @click="handleSubmit">保存修改</wd-button>
-        </view>
-      </view>
-    </view>
-  </view>
-</template>
-
-<script lang="ts" setup>
-import { ref } from 'vue'
-import { useUserStore } from '@/store'
-import { storeToRefs } from 'pinia'
-import { toast } from '@/utils/toast'
-import { updateInfo, updateUserPassword } from '@/api/login'
-
-// 表单引用
-const formRef = ref()
-
-// 用户信息
-const userStore = useUserStore()
-const { userInfo } = storeToRefs(userStore)
-
-// 表单数据
-const formData = ref({
-  id: userInfo.value.id,
-  oldPassword: '',
-  newPassword: '',
-  confirmPassword: '',
-})
-
-// 提交表单
-const handleSubmit = async () => {
-  // 表单验证
-  const valid = await formRef.value.validate()
-  if (!valid) return
-  const { message } = await updateUserPassword(formData.value)
-  await useUserStore().logout()
-  toast.success('修改成功,请重新登录')
-}
-</script>
-
-<style lang="scss" scoped>
-.profile-info-container {
-  min-height: 100vh;
-  background-color: #f5f7fa;
-  padding: 30rpx;
-}
-
-.profile-card {
-  background-color: #ffffff;
-  border-radius: 24rpx;
-  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.04);
-  overflow: hidden;
-}
-
-.card-header {
-  padding: 40rpx 30rpx 20rpx;
-  border-bottom: 2rpx solid #f0f0f0;
-}
-
-.card-title {
-  font-size: 36rpx;
-  font-weight: 600;
-  color: #333;
-  position: relative;
-  display: inline-block;
-  padding-bottom: 16rpx;
-
-  &::after {
-    content: '';
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    width: 60rpx;
-    height: 6rpx;
-    background: linear-gradient(90deg, #4a7bff, #6a5acd);
-    border-radius: 6rpx;
-  }
-}
-
-.form-wrapper {
-  padding: 30rpx;
-}
-
-.form-group {
-  border-radius: 16rpx;
-  overflow: hidden;
-  margin-bottom: 40rpx;
-}
-
-.form-input {
-  font-size: 30rpx;
-}
-
-.sex-field {
-  display: flex;
-  align-items: center;
-  padding: 24rpx 30rpx;
-  background-color: #ffffff;
-}
-
-.field-label {
-  width: 160rpx;
-  font-size: 30rpx;
-  color: #333;
-}
-
-.radio-group {
-  flex: 1;
-  display: flex;
-  gap: 20rpx;
-}
-
-.radio-btn {
-  flex: 1;
-  height: 80rpx;
-  line-height: 80rpx;
-  text-align: center;
-  font-size: 30rpx;
-  border-radius: 12rpx;
-  background-color: #f5f7fa;
-
-  &:active {
-    opacity: 0.8;
-  }
-}
-
-.form-actions {
-  display: flex;
-  flex-direction: row;
-  gap: 20rpx;
-}
-
-.submit-btn {
-  height: 90rpx;
-  border-radius: 45rpx;
-  font-size: 32rpx;
-  font-weight: 500;
-  background: linear-gradient(135deg, #4a7bff, #6a5acd);
-  box-shadow: 0 8rpx 16rpx rgba(74, 123, 255, 0.2);
-  transition: all 0.3s ease;
-
-  &:active {
-    transform: translateY(2rpx);
-    box-shadow: 0 4rpx 8rpx rgba(74, 123, 255, 0.15);
-  }
-}
-</style>