tj
2025-05-27 fa74612c99459a8b4e94121d2d3bfcc42915208b
loading,wechatLogin
已修改13个文件
已添加1个文件
600 ■■■■ 文件已修改
App.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
components/tabbar/top-tab-bar.vue 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
main.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
manifest.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages.json 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.vue 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/login.vue 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
plugins/http.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index copy.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index.js 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/index.ts 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
store/user.ts 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
types/index.ts 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/time.ts 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
App.vue
@@ -1,7 +1,12 @@
<script setup lang="ts">
import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
onLaunch(async (options: any) => {
  // 初始化用户状态
  userStore.initLoginState()
  const query = options.q ? decodeURIComponent(options.q) : ''
  const querydto: Record<string, string> = {}
@@ -37,7 +42,6 @@
  uni.getSystemSetting({
    success: (e: any) => {
      debugger;
      try {
        const custom = uni.getMenuButtonBoundingClientRect()
        uni.setStorageSync('StatusBar', e.statusBarHeight)
components/tabbar/top-tab-bar.vue
@@ -21,7 +21,7 @@
        <!-- 右侧按钮 -->
        <view class="right">
          <view class="login-view" @click="goLogin">
          <view class="login-view" @click="goLogin" v-if="!isLoggedIn">
            <up-icon name="/static/images/tabbar/user.png" size="30rpx" />
            <text class="login-text">登录</text>
          </view>
@@ -33,10 +33,12 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
const CustomBar = ref<number>(uni.getStorageSync('CustomBar') || 0)
const StatusBar = ref<number>(uni.getStorageSync('StatusBar') || 0)
import { ref, onMounted ,computed} from 'vue'
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
const isLoggedIn = computed(() => userStore.hasLogin)
console.log("登录状态")
console.log(isLoggedIn.value)
// 可选:自动获取系统信息进行替代
onMounted(() => {
main.js
@@ -4,7 +4,7 @@
import { createPinia } from 'pinia'
import message from './plugins/message'
import http from './plugins/http.js'
import store from './store'
// import store from './store/index.js'
// #ifndef VUE3
import Vue from 'vue'
@@ -53,7 +53,7 @@
 // 全局属性
  app.config.globalProperties.$message = message
  app.config.globalProperties.$http = http
  app.config.globalProperties.$store = store
  // app.config.globalProperties.$store = store
 
  // uni.$u.setConfig({
  //   config: {
manifest.json
@@ -50,8 +50,8 @@
    "quickapp" : {},
    /* 小程序特有相关 */
    "mp-weixin" : {
        // "appid" : "wx1441324401626290",
        "appid" : "wxede6e3ad8e89693a",
        "appid" : "wx1441324401626290",
        // "appid" : "wxede6e3ad8e89693a",
        "setting" : {
            "urlCheck" : false
        },
pages.json
@@ -12,7 +12,9 @@
        {
            "path": "pages/home/home",
            "style": {
                "navigationBarTitleText": "片场"
                "navigationBarTitleText": "片场",
                "enablePullDownRefresh": true,
                "onReachBottomDistance": 50
            }
        },
        {
pages/home/home.vue
@@ -43,7 +43,11 @@
      <Community v-for="(item, index) in communitys" :key="index" :avatar="item.avatar" :nickname="item.nickname"
        :time="formatRelativeTime(item.createTime)" :image="item.coverUrl" :content="item.coverAlt"
        :likeCount="item.likeCount" :commentCount="item.commentCount" />
      <view class="more">
        <!-- <view v-if="loadingCommunity">加载中...</view>
        <view v-if="noMoreCommunity">没有更多了</view> -->
        <up-loadmore :status="communityStatus" />
      </view>
      <view style="height: 300rpx;"></view>
    </view>
@@ -53,7 +57,7 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { onShow, onPullDownRefresh,onReachBottom } from '@dcloudio/uni-app'
import HomeMain from './home-main.vue'
import TripCard from './trip-card.vue'
@@ -67,6 +71,7 @@
import { FilmWorks } from '@/types/index'
import { formatRelativeTime } from '@/utils/time'
import { FilmWorksCategory } from '@/enums/dict'
// 主题
const theme = ref('light')
@@ -135,22 +140,68 @@
  getCommunitys()
});
async function getContentSelected() {
  tripCardList.value = await getFilmWorks(FilmWorksCategory.CONTENT_SELECTED, 20);
  console.log('内容精选', tripCardList.value);
onPullDownRefresh(async () => {
  console.log('用户下拉刷新了')
  // 内容精选
  getContentSelected()
  // 光影社区
  communityPage.value=1
  getCommunitys()
  uni.stopPullDownRefresh() // 停止下拉刷新动画
})
onReachBottom(()=>{
  console.log('用户触底了')
  getCommunitys()
})
const getContentSelected = async () => {
  tripCardList.value = await getFilmWorks(FilmWorksCategory.CONTENT_SELECTED, 20,1);
}
async function getCommunitys() {
  communitys.value = await getFilmWorks(FilmWorksCategory.COMMUNITY, 10);
const communityPage = ref(1)
const communitySize = 10
const communityStatus = ref('loading')
const getCommunitys = async () => {
  if (communityStatus.value==='nomore') return
  communityStatus.value = 'loading'
  const records = await getFilmWorks(FilmWorksCategory.COMMUNITY, communitySize, communityPage.value)
  if (records && records.length > 0) {
    // 使用 Set 进行去重
    const existingIds = new Set(communitys.value.map(item => item.id))
    const uniqueRecords = records.filter(item => !existingIds.has(item.id))
    communitys.value = [...communitys.value, ...uniqueRecords]
    // 如果返回的记录数少于请求的 size,说明没有更多数据
    if (records.length < communitySize) {
      communityStatus.value = 'noMore'
    }
    communityPage.value++
  } else {
    communityStatus.value = 'noMore'
  }
}
const getCommunitys_bak = async () => {
  communitys.value = await getFilmWorks(FilmWorksCategory.COMMUNITY, 10,1);
}
// 内容精选
const getFilmWorks = async (type: String, pageSize: Number) => {
const getFilmWorks = async (type: String, pageSize: Number,currentPage: Number) => {
  const {
    code, data
  } = await $http.request('get', '/api/filmWorks/list', {
    params: {
      classify: type,
      size: pageSize,
      current: currentPage
    }
  })
  if (code == 0) {
pages/login/login.vue
@@ -50,8 +50,11 @@
import { onShow } from '@dcloudio/uni-app'
import { useGlobal } from '@/composables/useGlobal'
import { usePlatformLoginType } from '@/composables/usePlatformLoginType'
import { useUserStore } from '@/store/user'
const { apitype } = usePlatformLoginType()
const { $http, $message,$store } = useGlobal()
const { $http, $message, $store } = useGlobal()
const userStore = useUserStore()
const isChecked = ref(false)
const toggleCheck = () => {
@@ -64,8 +67,29 @@
        uni.showToast({ title: '请先同意协议', icon: 'none' });
        return;
    }
    // 微信登录逻辑
    uni.showToast({ title: '微信登录', icon: 'success' });
    // 微信登录
    uni.login({
        "provider": "weixin",
        "onlyAuthorize": true, // 微信登录仅请求授权认证
        success: async function (event:any) {
            const { code } = event
            $message.showLoading();
            const resp = await userStore.loginwx({ code, phoneNumber: wxUser.value.phoneNumber, purePhoneNumber: wxUser.value.purePhoneNumber })
            if (resp && resp.data) {
                // that.$forceUpdate()
                uni.reLaunch({
                    url: '/pages/home/home'
                })
            }
            $message.hideLoading();
        },
        fail: function (err:any) {
            // 登录授权失败
            // err.code是错误码
        }
    })
};
onShow(() => {
@@ -77,13 +101,8 @@
        "provider": "weixin",
        "onlyAuthorize": true, // 微信登录仅请求授权认证
        success: async function (event: any) {
            console.log("aaaa")
            console.log(event)
            const { code } = event
            let openIdExistFlag = await getExistUserByOpenId(code);
            console.log(openIdExistFlag)
            console.log(wxUser.value)
        },
        fail: function (err: any) {
            // 登录授权失败
@@ -101,8 +120,6 @@
        }
    })
    if (code == 0) {
        console.log("查看当前用户是否已经绑定过")
        console.log(data)
        wxUser.value = data
        if (wxUser && wxUser.user) {
            return true
@@ -113,16 +130,13 @@
    }
}
const handleGetPhoneNumber = async (e:any) => {
const handleGetPhoneNumber = async (e: any) => {
    if (!isChecked.value) {
        $message.showToast('请同意用户协议')
        return
    }
    debugger;
    console.log(e)
    console.log(e.detail.code)  // 动态令牌
    console.log(e.detail.errMsg) // 回调信息(成功失败都会返回)
    console.log(e.detail.errno)  // 错误码(失败时返回)
    if (e.detail.errMsg == 'getPhoneNumber:ok') {
        console.log('获取成功')
        const {
@@ -134,13 +148,13 @@
            }
        })
        if (code == 0) {
            debugger;
            // 获取手机号码后,实现微信登录
            console.log(data)
            const phoneNumber = data.phone_info.phoneNumber;
            const purePhoneNumber = data.phone_info.purePhoneNumber;
            wxUser.value.phoneNumber = phoneNumber
            wxUser.value.purePhoneNumber = purePhoneNumber
            // that.handleWechatClick()
            handleWechatClick()
        } else {
        }
@@ -153,10 +167,11 @@
    uni.login({
        "provider": "weixin",
        "onlyAuthorize": true, // 微信登录仅请求授权认证
        success: async function (event) {
        success: async function (event: any) {
            const { code } = event
            $message.showLoading();
            const resp = await $store.dispatch('loginwx', { code, phoneNumber: wxUser.phoneNumber, purePhoneNumber: wxUser.purePhoneNumber })
            console.log("获取到的微信用户信息是:", wxUser.value)
            const resp = await userStore.loginwx({ code, phoneNumber: wxUser.value.phoneNumber, purePhoneNumber: wxUser.value.purePhoneNumber })
            if (resp && resp.data) {
                // $forceUpdate()
                uni.reLaunch({
@@ -165,7 +180,7 @@
            }
            $message.hideLoading();
        },
        fail: function (err) {
        fail: function (err: any) {
            // 登录授权失败
            // err.code是错误码
        }
plugins/http.js
@@ -1,7 +1,7 @@
import environments from '@/environments'
import message from './message'
import storage from './storage'
import store from '../store'
// import store from '../store'
import utils from './util.js'
let pre = 'api'
@@ -107,7 +107,8 @@
                                console.log('resp', res)
                                // storage.removeItem('token')
                                // await store.dispatch('logout')
                                store.commit('updateLogin', false)
                                // TODO
                                // store.commit('updateLogin', false)
                                await message.showToast('登录信息失效')
@@ -152,7 +153,8 @@
                        console.log('401', res)
                        // storage.removeItem('token')
                        // await store.dispatch('logout')
                        store.commit('updateLogin', false)
                        // TODO
                        // store.commit('updateLogin', false)
                        await message.showToast('登录信息失效')
store/index copy.js
@@ -1,4 +1,4 @@
import http from '../plugins/http'
import http from '../plugins/http.js'
import storage from '../plugins/storage.js'
import message from '../plugins/message.js'
import Vue from 'vue'
store/index.js
@@ -1,229 +0,0 @@
// store/index.js
import { createStore } from 'vuex'
import http from '../plugins/http'
import storage from '../plugins/storage.js'
import message from '../plugins/message.js'
const store = createStore({
  state() {
    return {
      hasLogin: false,
      isUniverifyLogin: false,
      loginProvider: '',
      openid: null,
      testvuex: false,
      colorIndex: 0,
      colorList: ['#FF0000', '#00FF00', '#0000FF'],
      noMatchLeftWindow: true,
      active: 'componentPage',
      leftWinActive: '/pages/component/view/view',
      activeOpen: '',
      menu: [],
      appMenu: [],
      univerifyErrorMsg: '',
      currentInfo: {},
      cache_address: {},
      sign: {
        enterprise: 0,
        info: 0,
        flower: 0,
        shopping: 0,
        follow: 0,
        delivery: 0,
        order: 0,
        shopnum: 0,
        coupon: 0,
        cache_topay: 0,
      },
      cache: {
        coupon: {},
        goods: [],
        cache_coupon_select_cancel: 0,
      },
      defaultaddress: {},
      addressDesc: '',
    }
  },
  mutations: {
    updateLogin(state, provider) {
      state.hasLogin = !!provider
      if (!state.hasLogin) {
        state.currentInfo = {}
        storage.removeItem('token')
      }
    },
    login(state, provider) {
      state.hasLogin = true
      state.loginProvider = provider
    },
    logout(state) {
      state.hasLogin = false
      state.openid = null
      state.currentInfo = {}
      state.appMenu = []
      storage.removeItem('token')
      storage.removeItem('appMenu')
      message.showToast('退出登录成功')
    },
    setOpenid(state, openid) {
      state.openid = openid
    },
    setDefaultAddress(state, defaultaddress) {
      state.defaultaddress = defaultaddress
    },
    setAddressDesc(state, addressDesc) {
      state.addressDesc = addressDesc
      storage.setItem('defaultaddress', addressDesc || '')
    },
    setTestTrue(state) {
      state.testvuex = true
    },
    setTestFalse(state) {
      state.testvuex = false
    },
    setColorIndex(state, index) {
      state.colorIndex = index
    },
    setActive(state, tabPage) {
      state.active = tabPage
    },
    setActiveOpen(state, activeOpen) {
      state.activeOpen = activeOpen
    },
    setMenu(state, menu) {
      state.menu = menu
    },
    setUniverifyLogin(state, payload) {
      state.isUniverifyLogin = !!payload
    },
    setUniverifyErrorMsg(state, payload = '') {
      state.univerifyErrorMsg = payload
    }
  },
  getters: {
    currentColor(state) {
      return state.colorList[state.colorIndex]
    }
  },
  actions: {
    async sign_add({ state }, key) {
      state.sign[key] = 1
    },
    async sign_clear({ state }, key) {
      state.sign[key] = 0
    },
    async cache_coupon_select({ state }, dto) {
      state.cache.coupon = dto || {}
    },
    async cache_coupon_select_cancel({ state }, val) {
      state.cache.cache_coupon_select_cancel = val || 0
    },
    async cache_goods_select({ state }, goods) {
      state.cache.goods = goods || []
    },
    async logout({ commit }) {
      commit('logout')
    },
    async getUserOpenId({ state, commit }) {
      if (state.openid) return state.openid
      return new Promise((resolve, reject) => {
        uni.login({
          success(data) {
            commit('login')
            setTimeout(() => {
              const openid = '123456789'
              commit('setOpenid', openid)
              resolve(openid)
            }, 1000)
          },
          fail(err) {
            reject(err)
          }
        })
      })
    },
    async getCurrentInfo({ commit, state }) {
      const currentInfo = await http.request('get', '/api/current/user', {})
      if (currentInfo && currentInfo.code === 0) {
        state.currentInfo = currentInfo.data || {}
        state.type = currentInfo.data.type || ''
        state.spacecode = currentInfo.data.spacecode || ''
        commit('updateLogin', true)
      } else {
        commit('updateLogin', false)
      }
    },
    async getSwitchSubAccount({ commit, state }, payload) {
      const currentInfo = await http.request('get', '/api/supplierSub/getSwitchById', {
        params: {
          id: payload.id,
          type: payload.type
        }
      })
      if (currentInfo && currentInfo.code === 0) {
        state.currentInfo = currentInfo.data || {}
        state.type = currentInfo.data.type || ''
        state.spacecode = currentInfo.data.spacecode || ''
        commit('updateLogin', true)
      } else {
        commit('updateLogin', false)
      }
      return currentInfo
    },
    async getAppMenu({ state }) {
      const menu = await http.request('get', '/api/app/menu/permission/menu', {})
      storage.setItem('appMenu', [])
      if (menu && menu.code === 0) {
        const appMenu = menu.data || []
        storage.setItem('appMenu', appMenu)
      }
    },
    async getAppMenuSupplier({ state }) {
      const menu = await http.request('get', '/api/app/menu/supplier/permission/menu', {})
      storage.setItem('appMenu', [])
      if (menu && menu.code === 0) {
        const appMenu = menu.data || []
        storage.setItem('appMenu', appMenu)
      }
    },
    async getAppMenuPartner({ state }) {
      const menu = await http.request('get', '/api/app/menu/partner/permission/menu', {})
      storage.setItem('appMenu', [])
      if (menu && menu.code === 0) {
        const appMenu = menu.data || []
        storage.setItem('appMenu', appMenu)
      }
    },
    async loginwx({ dispatch, state }, data) {
      const resp = await http.request('post', '/api/login/wechat', {
        data: {
          code: data.code,
          imgurl: data.imgurl || '',
          nickname: data.nickname || '',
          inviter: data.inviter || '',
          phoneNumber: data.phoneNumber || '',
          purePhoneNumber: data.purePhoneNumber || '',
        }
      })
      if (resp && resp.code === 0) {
        state.isBind = true
        storage.setItem('token', resp.data.access_token || '')
        state.hasLogin = true
        if (data.inviter) {
          storage.removeItem('inviter')
          storage.removeItem('inviterTime')
          storage.removeItem('inviterName')
        }
        await dispatch('getCurrentInfo')
      } else {
        message.showToast('登录失败: ' + (resp && resp.msg))
        storage.removeItem('openid')
        storage.removeItem('tel')
        storage.removeItem('token')
      }
      return resp
    }
  }
})
export default store
store/index.ts
对比新文件
@@ -0,0 +1,69 @@
// stores/user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import http from '@/plugins/http.js' // 请替换成你实际的 http 封装路径
import storage from '@/plugins/storage' // 同样替换为你的封装路径
import message from '@/plugins/message' // 你使用的消息组件封装
import { WechatLoginData } from '@/types/index'
export const useUserStore = defineStore('user', () => {
  const hasLogin = ref(false)
  const isBind = ref(false)
  async function getCurrentInfo() {
    // 模拟请求用户信息
    console.log('获取当前用户信息')
    // 这里你可以请求 /api/user/info 等接口获取用户数据
  }
  async function loginwx(data: WechatLoginData) {
    const {
      code,
      imgurl = '',
      nickname = '',
      inviter = '',
      phoneNumber = '',
      purePhoneNumber = ''
    } = data
    const resp = await http.request('post', '/api/login/wechat', {
      data: {
        code,
        imgurl,
        nickname,
        inviter,
        phoneNumber,
        purePhoneNumber
      }
    })
    if (resp && resp.code === 0) {
      isBind.value = true
      storage.setItem('token', resp.data.access_token || '')
      hasLogin.value = true
      if (inviter) {
        storage.removeItem('inviter')
        storage.removeItem('inviterTime')
        storage.removeItem('inviterName')
      }
      await getCurrentInfo()
    } else {
      message.showToast('登录失败:' + (resp?.msg || '未知错误'))
      storage.removeItem('openid')
      storage.removeItem('tel')
      storage.removeItem('token')
    }
    return resp
  }
  return {
    hasLogin,
    isBind,
    loginwx,
    getCurrentInfo
  }
})
store/user.ts
@@ -1,6 +1,88 @@
// stores/user.ts
import { defineStore } from 'pinia'
import { ref } from 'vue'
import http from '@/plugins/http.js' // 请替换成你实际的 http 封装路径
import storage from '@/plugins/storage' // 同样替换为你的封装路径
import message from '@/plugins/message' // 你使用的消息组件封装
import { WechatLoginData } from '@/types/index'
export const useUserStore = defineStore('user', () => {
})
    const hasLogin = ref(false)
    const isBind = ref(false)
    const userInfo = ref<any>(null)
    async function getCurrentInfo() {
        const currentInfo = await http.request('get', '/api/current/user', {})
        if (currentInfo && currentInfo.code == 0) {
            console.log('当前用户信息', currentInfo)
            userInfo.value = currentInfo.data // 赋值到 store
        } else {
            message.showToast('获取用户信息失败')
        }
    }
    async function loginwx(data: WechatLoginData) {
        const {
            code,
            imgurl = '',
            nickname = '',
            inviter = '',
            phoneNumber = '',
            purePhoneNumber = ''
        } = data
        const resp = await http.request('post', '/api/login/wechat', {
            data: {
                code,
                imgurl,
                nickname,
                inviter,
                phoneNumber,
                purePhoneNumber
            }
        })
        if (resp && resp.code === 0) {
            isBind.value = true
            storage.setItem('token', resp.data.access_token || '')
            hasLogin.value = true
            await getCurrentInfo()
        } else {
            message.showToast('登录失败:' + (resp?.msg || '未知错误'))
            storage.removeItem('openid')
            storage.removeItem('tel')
            storage.removeItem('token')
        }
        return resp
    }
    function initLoginState() {
        const token = storage.getItem('token')
        if (token) {
          hasLogin.value = true
          const savedUserInfo = storage.getItem('userInfo')
          if (savedUserInfo) {
            userInfo.value = savedUserInfo
          } else {
            getCurrentInfo()
          }
        } else {
          hasLogin.value = false
        }
      }
    return {
        hasLogin,
        isBind,
        userInfo,
        loginwx,
        getCurrentInfo,
        initLoginState,
    }
})
types/index.ts
@@ -1,9 +1,3 @@
export interface ProtocolData {
    id: number;
    title: string;
    content: string;
}
export interface WxUser {
    openId: String;
    sessionKey: String;
@@ -13,6 +7,21 @@
    purePhoneNumber: String;
}
export interface WechatLoginData {
  code: string
  imgurl?: string
  nickname?: string
  inviter?: string
  phoneNumber?: string
  purePhoneNumber?: string
}
export interface ProtocolData {
    id: number;
    title: string;
    content: string;
}
export interface FilmWorks{
    id?: number;
utils/time.ts
@@ -1,6 +1,35 @@
// utils/time.ts
export function formatRelativeTime(inputTime: string | Date): string {
  const now = new Date()
  // 如果是字符串格式,先进行兼容性处理
  let time: Date
  if (typeof inputTime === 'string') {
    // 替换中间的空格为 'T' 或替换 '-' 为 '/'
    const compatibleStr = inputTime.replace(/-/g, '/')
    time = new Date(compatibleStr)
  } else {
    time = inputTime
  }
  const diffMs = now.getTime() - time.getTime()
  const minutes = Math.floor(diffMs / (1000 * 60))
  const hours = Math.floor(minutes / 60)
  const days = Math.floor(hours / 24)
  const months = Math.floor(days / 30)
  const years = Math.floor(days / 365)
  if (years > 0) return `${years} 年前`
  if (months > 0) return `${months} 个月前`
  if (days > 0) return `${days} 天前`
  if (hours > 0) return `${hours} 小时前`
  if (minutes > 0) return `${minutes} 分钟前`
  return '刚刚'
}
export function formatRelativeTime2(inputTime: string | Date): string {
    const now = new Date()
    const time = typeof inputTime === 'string' ? new Date(inputTime) : inputTime
    const diffMs = now.getTime() - time.getTime()