refactor: 项目架构清理 — 删除调试页面/冗余store/H5降级代码/无用文件
This commit is contained in:
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
VITE_API_BASE_URL=http://localhost:80
|
VITE_API_BASE_URL=http://localhost:48080
|
||||||
VITE_APP_TITLE=湖南12301文旅专区
|
VITE_APP_TITLE=湖南12301文旅专区
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
// app.js
|
|
||||||
App({
|
|
||||||
onLaunch() {
|
|
||||||
// 展示本地存储能力
|
|
||||||
const logs = wx.getStorageSync('logs') || []
|
|
||||||
logs.unshift(Date.now())
|
|
||||||
wx.setStorageSync('logs', logs)
|
|
||||||
|
|
||||||
// 登录
|
|
||||||
wx.login({
|
|
||||||
success: res => {
|
|
||||||
// 发送 res.code 到后台换取 openId, sessionKey, unionId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
globalData: {
|
|
||||||
userInfo: null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"pages": [
|
|
||||||
"pages/index/index",
|
|
||||||
"pages/logs/logs"
|
|
||||||
],
|
|
||||||
"window": {
|
|
||||||
"navigationBarTextStyle": "black",
|
|
||||||
"navigationBarTitleText": "Weixin",
|
|
||||||
"navigationBarBackgroundColor": "#ffffff"
|
|
||||||
},
|
|
||||||
"style": "v2",
|
|
||||||
"componentFramework": "glass-easel",
|
|
||||||
"sitemapLocation": "sitemap.json",
|
|
||||||
"lazyCodeLoading": "requiredComponents"
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
/**app.wxss**/
|
|
||||||
.container {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 200rpx 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// index.js
|
|
||||||
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
|
||||||
|
|
||||||
Page({
|
|
||||||
data: {
|
|
||||||
motto: 'Hello World',
|
|
||||||
userInfo: {
|
|
||||||
avatarUrl: defaultAvatarUrl,
|
|
||||||
nickName: '',
|
|
||||||
},
|
|
||||||
hasUserInfo: false,
|
|
||||||
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
|
|
||||||
canIUseNicknameComp: wx.canIUse('input.type.nickname'),
|
|
||||||
},
|
|
||||||
bindViewTap() {
|
|
||||||
wx.navigateTo({
|
|
||||||
url: '../logs/logs'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onChooseAvatar(e) {
|
|
||||||
const { avatarUrl } = e.detail
|
|
||||||
const { nickName } = this.data.userInfo
|
|
||||||
this.setData({
|
|
||||||
"userInfo.avatarUrl": avatarUrl,
|
|
||||||
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
onInputChange(e) {
|
|
||||||
const nickName = e.detail.value
|
|
||||||
const { avatarUrl } = this.data.userInfo
|
|
||||||
this.setData({
|
|
||||||
"userInfo.nickName": nickName,
|
|
||||||
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getUserProfile(e) {
|
|
||||||
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
|
|
||||||
wx.getUserProfile({
|
|
||||||
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
|
||||||
success: (res) => {
|
|
||||||
console.log(res)
|
|
||||||
this.setData({
|
|
||||||
userInfo: res.userInfo,
|
|
||||||
hasUserInfo: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"usingComponents": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<!--index.wxml-->
|
|
||||||
<scroll-view class="scrollarea" scroll-y type="list">
|
|
||||||
<view class="container">
|
|
||||||
<view class="userinfo">
|
|
||||||
<block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
|
|
||||||
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
|
|
||||||
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
|
|
||||||
</button>
|
|
||||||
<view class="nickname-wrapper">
|
|
||||||
<text class="nickname-label">昵称</text>
|
|
||||||
<input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
|
|
||||||
</view>
|
|
||||||
</block>
|
|
||||||
<block wx:elif="{{!hasUserInfo}}">
|
|
||||||
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
|
|
||||||
<view wx:else> 请使用2.10.4及以上版本基础库 </view>
|
|
||||||
</block>
|
|
||||||
<block wx:else>
|
|
||||||
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
|
|
||||||
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
|
|
||||||
</block>
|
|
||||||
</view>
|
|
||||||
<view class="usermotto">
|
|
||||||
<text class="user-motto">{{motto}}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/**index.wxss**/
|
|
||||||
page {
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.scrollarea {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.userinfo {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
color: #aaa;
|
|
||||||
width: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.userinfo-avatar {
|
|
||||||
overflow: hidden;
|
|
||||||
width: 128rpx;
|
|
||||||
height: 128rpx;
|
|
||||||
margin: 20rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.usermotto {
|
|
||||||
margin-top: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-wrapper {
|
|
||||||
padding: 0;
|
|
||||||
width: 56px !important;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-top: 40px;
|
|
||||||
margin-bottom: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar {
|
|
||||||
display: block;
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nickname-wrapper {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
padding: 16px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-top: .5px solid rgba(0, 0, 0, 0.1);
|
|
||||||
border-bottom: .5px solid rgba(0, 0, 0, 0.1);
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nickname-label {
|
|
||||||
width: 105px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nickname-input {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
|
|
||||||
"rules": [{
|
|
||||||
"action": "allow",
|
|
||||||
"page": "*"
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export * from './types'
|
|
||||||
export * from './user'
|
|
||||||
export * from './card'
|
|
||||||
export * from './order'
|
|
||||||
export { get, post, put, del, getToken, setToken, removeToken } from './request'
|
|
||||||
@@ -16,12 +16,6 @@ export interface WxLoginResult {
|
|||||||
expiresTime: string
|
expiresTime: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 账号密码登录参数(降级方案) */
|
|
||||||
export interface LoginParams {
|
|
||||||
username: string
|
|
||||||
password: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 年卡基本信息 */
|
/** 年卡基本信息 */
|
||||||
export interface CardInfo {
|
export interface CardInfo {
|
||||||
id: string
|
id: string
|
||||||
|
|||||||
+2
-7
@@ -1,19 +1,14 @@
|
|||||||
import { get, post } from './request'
|
import { get, post } from './request'
|
||||||
import type { UserInfo, WxLoginResult, LoginParams } from './types'
|
import type { UserInfo, WxLoginResult } from './types'
|
||||||
|
|
||||||
/** 微信小程序登录(loginCode + phoneCode) */
|
/** 微信小程序登录(loginCode + phoneCode) */
|
||||||
export function wxLogin(data: { loginCode: string; phoneCode: string }): Promise<WxLoginResult> {
|
export function wxLogin(data: { loginCode: string; phoneCode: string }): Promise<WxLoginResult> {
|
||||||
return post<WxLoginResult>('/auth/wx-login', data, false)
|
return post<WxLoginResult>('/auth/wx-login', data, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 账号密码登录(降级方案) */
|
|
||||||
export function login(params: LoginParams): Promise<WxLoginResult> {
|
|
||||||
return post<WxLoginResult>('/auth/login', params, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前用户信息 */
|
/** 获取当前用户信息 */
|
||||||
export function getUserInfo(): Promise<UserInfo> {
|
export function getUserInfo(): Promise<UserInfo> {
|
||||||
return get<UserInfo>('/user/info')
|
return get<UserInfo>('/user/info')
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { UserInfo, WxLoginResult, LoginParams }
|
export type { UserInfo, WxLoginResult }
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!-- 通用毛玻璃卡片 -->
|
||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<view class="mc-glass" :class="customClass">
|
||||||
|
<!-- 左上高光切面 -->
|
||||||
|
<view class="mc-glass-cut" />
|
||||||
|
<!-- 内容层 -->
|
||||||
|
<view class="mc-glass-body" @click.stop>
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
.mc-glass {
|
||||||
|
position: relative;
|
||||||
|
background-color: rgba(255, 255, 255, 0.10);
|
||||||
|
backdrop-filter: blur(24rpx) saturate(1.4);
|
||||||
|
-webkit-backdrop-filter: blur(24rpx) saturate(1.4);
|
||||||
|
border-width: 1rpx;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: rgba(255, 255, 255, 0.10);
|
||||||
|
border-radius: 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.mc-glass-cut {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
background-image: linear-gradient(160deg, rgba(255,255,255,0.08) 0%, transparent 40%, transparent 70%, rgba(255,255,255,0.04) 100%);
|
||||||
|
}
|
||||||
|
.mc-glass-body {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
/* hover 增强 */
|
||||||
|
.mc-glass-hover .mc-glass {
|
||||||
|
background-color: rgba(255, 255, 255, 0.14) !important;
|
||||||
|
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.35) !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1 +1,11 @@
|
|||||||
{
|
{
|
||||||
|
"mp-weixin": {
|
||||||
|
"appid": "wx636bc46a6570e9fd",
|
||||||
|
"setting": {
|
||||||
|
"urlCheck": false,
|
||||||
|
"es6": true,
|
||||||
|
"postcss": false,
|
||||||
|
"minified": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,10 +32,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useCardStore } from '../../../../store/card'
|
import { activateCard } from '../../../../api/card'
|
||||||
import { showToast } from '../../../../utils'
|
import { showToast } from '../../../../utils'
|
||||||
|
|
||||||
const cardStore = useCardStore()
|
|
||||||
const cardId = ref('')
|
const cardId = ref('')
|
||||||
const cardName = ref('')
|
const cardName = ref('')
|
||||||
const activating = ref(false)
|
const activating = ref(false)
|
||||||
@@ -76,7 +75,7 @@ async function handleActivate() {
|
|||||||
if (!cardId.value) return
|
if (!cardId.value) return
|
||||||
activating.value = true
|
activating.value = true
|
||||||
try {
|
try {
|
||||||
await cardStore.activateCard(cardId.value, form)
|
await activateCard(cardId.value, form)
|
||||||
showToast('激活成功', 'success')
|
showToast('激活成功', 'success')
|
||||||
// 激活成功后跳转入园码页
|
// 激活成功后跳转入园码页
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@@ -23,10 +23,9 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useCardStore } from '../../../../store/card'
|
import { bindCard } from '../../../../api/card'
|
||||||
import { showToast } from '../../../../utils'
|
import { showToast } from '../../../../utils'
|
||||||
|
|
||||||
const cardStore = useCardStore()
|
|
||||||
const cardNo = ref('')
|
const cardNo = ref('')
|
||||||
const binding = ref(false)
|
const binding = ref(false)
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ async function handleBind() {
|
|||||||
}
|
}
|
||||||
binding.value = true
|
binding.value = true
|
||||||
try {
|
try {
|
||||||
await cardStore.bindCard(cardNo.value.trim())
|
await bindCard(cardNo.value.trim())
|
||||||
showToast('绑定成功', 'success')
|
showToast('绑定成功', 'success')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
uni.navigateBack()
|
uni.navigateBack()
|
||||||
|
|||||||
@@ -54,10 +54,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useCardStore } from '../../../../store/card'
|
import { getCardDetail } from '../../../../api/card'
|
||||||
import type { CardDetail } from '../../../../api/types'
|
import type { CardDetail } from '../../../../api/types'
|
||||||
|
|
||||||
const cardStore = useCardStore()
|
|
||||||
const card = ref<CardDetail | null>(null)
|
const card = ref<CardDetail | null>(null)
|
||||||
|
|
||||||
/** 页面加载时获取年卡详情 */
|
/** 页面加载时获取年卡详情 */
|
||||||
@@ -70,8 +69,7 @@ onLoad((options) => {
|
|||||||
/** 加载年卡详情数据 */
|
/** 加载年卡详情数据 */
|
||||||
async function loadDetail(id: string) {
|
async function loadDetail(id: string) {
|
||||||
try {
|
try {
|
||||||
await cardStore.fetchCardDetail(id)
|
card.value = await getCardDetail(id)
|
||||||
card.value = cardStore.currentCard
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
uni.showToast({ title: '加载失败', icon: 'none' })
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,12 @@
|
|||||||
</view>
|
</view>
|
||||||
<!-- 年卡列表 -->
|
<!-- 年卡列表 -->
|
||||||
<view class="card-list">
|
<view class="card-list">
|
||||||
<view v-if="cardStore.loading" class="loading"><text>加载中...</text></view>
|
<view v-if="loading" class="loading"><text>加载中...</text></view>
|
||||||
<view v-else-if="cardStore.cardList.length === 0">
|
<view v-else-if="cardList.length === 0">
|
||||||
<empty-state icon="🎫" text="暂无符合条件的年卡" />
|
<empty-state icon="🎫" text="暂无符合条件的年卡" />
|
||||||
</view>
|
</view>
|
||||||
<view v-else>
|
<view v-else>
|
||||||
<card-item v-for="card in cardStore.cardList" :key="card.id" :card="card" @click="goDetail" />
|
<card-item v-for="card in cardList" :key="card.id" :card="card" @click="goDetail" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -32,12 +32,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useCardStore } from '../../../../store/card'
|
import { getCardList } from '../../../../api/card'
|
||||||
import CardItem from '../../../../components/card-item.vue'
|
import CardItem from '../../../../components/card-item.vue'
|
||||||
import EmptyState from '../../../../components/empty-state.vue'
|
import EmptyState from '../../../../components/empty-state.vue'
|
||||||
import type { CardInfo } from '../../../../api/types'
|
import type { CardInfo } from '../../../../api/types'
|
||||||
|
|
||||||
const cardStore = useCardStore()
|
const cardList = ref<CardInfo[]>([])
|
||||||
|
const loading = ref(false)
|
||||||
const keyword = ref('')
|
const keyword = ref('')
|
||||||
const currentCategory = ref('')
|
const currentCategory = ref('')
|
||||||
|
|
||||||
@@ -49,14 +50,24 @@ const categories = [
|
|||||||
{ label: '情侣年卡', value: 'couple' }
|
{ label: '情侣年卡', value: 'couple' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/** 获取年卡列表 */
|
||||||
|
async function fetchCardList(params?: { keyword?: string; category?: string }) {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
cardList.value = await getCardList(params)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** 页面加载时获取年卡列表 */
|
/** 页面加载时获取年卡列表 */
|
||||||
onLoad(() => {
|
onLoad(() => {
|
||||||
cardStore.fetchCardList()
|
fetchCardList()
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 执行搜索 */
|
/** 执行搜索 */
|
||||||
function handleSearch() {
|
function handleSearch() {
|
||||||
cardStore.fetchCardList({ keyword: keyword.value, category: currentCategory.value })
|
fetchCardList({ keyword: keyword.value, category: currentCategory.value })
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 选择分类 */
|
/** 选择分类 */
|
||||||
|
|||||||
@@ -25,11 +25,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onBeforeUnmount } from 'vue'
|
import { ref, onBeforeUnmount } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { useCardStore } from '../../../../store/card'
|
import { getEntryQrCode } from '../../../../api/card'
|
||||||
import { showToast } from '../../../../utils'
|
import { showToast } from '../../../../utils'
|
||||||
import type { QrCodeInfo } from '../../../../api/types'
|
import type { QrCodeInfo } from '../../../../api/types'
|
||||||
|
|
||||||
const cardStore = useCardStore()
|
|
||||||
const cardId = ref('')
|
const cardId = ref('')
|
||||||
const qrInfo = ref<QrCodeInfo | null>(null)
|
const qrInfo = ref<QrCodeInfo | null>(null)
|
||||||
let refreshTimer: ReturnType<typeof setInterval> | null = null
|
let refreshTimer: ReturnType<typeof setInterval> | null = null
|
||||||
@@ -54,7 +53,7 @@ onBeforeUnmount(() => {
|
|||||||
/** 加载入园码 */
|
/** 加载入园码 */
|
||||||
async function loadQrCode() {
|
async function loadQrCode() {
|
||||||
try {
|
try {
|
||||||
qrInfo.value = await cardStore.getEntryQrCode(cardId.value)
|
qrInfo.value = await getEntryQrCode(cardId.value)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
showToast(err.message || '获取入园码失败')
|
showToast(err.message || '获取入园码失败')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="page">
|
|
||||||
<!-- 顶部标题区 -->
|
|
||||||
<view class="header">
|
|
||||||
<text class="header-title">湖南12301文旅专区</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 宫格功能入口 -->
|
|
||||||
<view class="grid">
|
|
||||||
<view class="grid-item" @click="goTo('/packages/user/pages/card/list')">
|
|
||||||
<view class="grid-icon" style="background: #E8F0FE;">
|
|
||||||
<text class="emoji">🎫</text>
|
|
||||||
</view>
|
|
||||||
<text class="grid-label">购买年卡</text>
|
|
||||||
<text class="grid-desc">多种卡种可选</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="grid-item" @click="goTo('/packages/user/pages/card/bind')">
|
|
||||||
<view class="grid-icon" style="background: #FFF3E0;">
|
|
||||||
<text class="emoji">📱</text>
|
|
||||||
</view>
|
|
||||||
<text class="grid-label">激活/绑定</text>
|
|
||||||
<text class="grid-desc">激活已购年卡</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="grid-item" @click="showComingSoon">
|
|
||||||
<view class="grid-icon" style="background: #E8F8F0;">
|
|
||||||
<text class="emoji">🏔️</text>
|
|
||||||
</view>
|
|
||||||
<text class="grid-label">景区预约</text>
|
|
||||||
<text class="grid-desc">预约入园时间</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="grid-item" @click="showComingSoon">
|
|
||||||
<view class="grid-icon" style="background: #FCE4EC;">
|
|
||||||
<text class="emoji">📋</text>
|
|
||||||
</view>
|
|
||||||
<text class="grid-label">我的记录</text>
|
|
||||||
<text class="grid-desc">预约/使用记录</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 推荐年卡 -->
|
|
||||||
<view class="section">
|
|
||||||
<view class="section-header">
|
|
||||||
<text class="section-title">推荐年卡</text>
|
|
||||||
<text class="section-more" @click="goTo('/packages/user/pages/card/list')">查看全部 ›</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-if="cardStore.loading" class="loading">
|
|
||||||
<text>加载中...</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-else-if="cardStore.cardList.length === 0" class="empty">
|
|
||||||
<empty-state icon="🎫" text="暂无年卡" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-else>
|
|
||||||
<card-item
|
|
||||||
v-for="card in displayCards"
|
|
||||||
:key="card.id"
|
|
||||||
:card="card"
|
|
||||||
@click="goToDetail"
|
|
||||||
/>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { computed } from 'vue'
|
|
||||||
import { onShow } from '@dcloudio/uni-app'
|
|
||||||
import { useCardStore } from '../../../../store/card'
|
|
||||||
import CardItem from '../../../../components/card-item.vue'
|
|
||||||
import EmptyState from '../../../../components/empty-state.vue'
|
|
||||||
import type { CardInfo } from '../../../../api/types'
|
|
||||||
|
|
||||||
const cardStore = useCardStore()
|
|
||||||
|
|
||||||
// 首页最多展示 3 张年卡
|
|
||||||
const displayCards = computed(() => cardStore.cardList.slice(0, 3))
|
|
||||||
|
|
||||||
onShow(() => {
|
|
||||||
cardStore.fetchCardList()
|
|
||||||
})
|
|
||||||
|
|
||||||
function goTo(url: string) {
|
|
||||||
uni.navigateTo({ url })
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToDetail(card: CardInfo) {
|
|
||||||
uni.navigateTo({ url: `/packages/user/pages/card/detail?id=${card.id}` })
|
|
||||||
}
|
|
||||||
|
|
||||||
function showComingSoon() {
|
|
||||||
uni.showToast({ title: '即将上线,敬请期待', icon: 'none' })
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.page {
|
|
||||||
min-height: 100vh;
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
background: #4A90D9;
|
|
||||||
padding: 40rpx 30rpx 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header-title {
|
|
||||||
font-size: 36rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
gap: 16rpx;
|
|
||||||
padding: 20rpx;
|
|
||||||
margin: -20rpx 16rpx 0;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 16rpx;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-item {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
padding: 24rpx 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-icon {
|
|
||||||
width: 100rpx;
|
|
||||||
height: 100rpx;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji {
|
|
||||||
font-size: 44rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-label {
|
|
||||||
font-size: 28rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 4rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid-desc {
|
|
||||||
font-size: 22rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
padding: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-more {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #4A90D9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
text-align: center;
|
|
||||||
padding: 60rpx;
|
|
||||||
color: #999;
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
+9
-15
@@ -9,7 +9,7 @@
|
|||||||
{
|
{
|
||||||
"path": "pages/index/index",
|
"path": "pages/index/index",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "湖南12301"
|
"navigationBarTitleText": "文旅专区"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -17,18 +17,18 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "登录"
|
"navigationBarTitleText": "登录"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/profile/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "个人中心"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"subPackages": [
|
"subPackages": [
|
||||||
{
|
{
|
||||||
"root": "packages/user",
|
"root": "packages/user",
|
||||||
"pages": [
|
"pages": [
|
||||||
{
|
|
||||||
"path": "pages/index/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "文旅专区"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "pages/card/list",
|
"path": "pages/card/list",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -64,12 +64,6 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "绑定年卡"
|
"navigationBarTitleText": "绑定年卡"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "pages/profile/index",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "个人中心"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -87,13 +81,13 @@
|
|||||||
"backgroundColor": "#ffffff",
|
"backgroundColor": "#ffffff",
|
||||||
"list": [
|
"list": [
|
||||||
{
|
{
|
||||||
"pagePath": "packages/user/pages/index/index",
|
"pagePath": "pages/index/index",
|
||||||
"text": "首页",
|
"text": "首页",
|
||||||
"iconPath": "static/tabbar/home.png",
|
"iconPath": "static/tabbar/home.png",
|
||||||
"selectedIconPath": "static/tabbar/home-active.png"
|
"selectedIconPath": "static/tabbar/home-active.png"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pagePath": "packages/user/pages/profile/index",
|
"pagePath": "pages/profile/index",
|
||||||
"text": "我的",
|
"text": "我的",
|
||||||
"iconPath": "static/tabbar/profile.png",
|
"iconPath": "static/tabbar/profile.png",
|
||||||
"selectedIconPath": "static/tabbar/profile-active.png"
|
"selectedIconPath": "static/tabbar/profile-active.png"
|
||||||
|
|||||||
+1
-107
@@ -7,36 +7,12 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="login-area">
|
<view class="login-area">
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
<button class="btn-wx-login"
|
<button class="btn-wx-login"
|
||||||
open-type="getPhoneNumber"
|
open-type="getPhoneNumber"
|
||||||
@getphonenumber="handleGetPhoneNumber"
|
@getphonenumber="handleGetPhoneNumber"
|
||||||
:disabled="loading">
|
:disabled="loading">
|
||||||
{{ loading ? '登录中...' : '微信一键登录' }}
|
{{ loading ? '登录中...' : '微信一键登录' }}
|
||||||
</button>
|
</button>
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- #ifdef H5 -->
|
|
||||||
<view class="h5-tip">
|
|
||||||
<text>请在微信小程序中使用本应用</text>
|
|
||||||
</view>
|
|
||||||
<view class="form" v-if="showFallback">
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="label">账号</text>
|
|
||||||
<input class="input" v-model="form.username" placeholder="请输入账号" />
|
|
||||||
</view>
|
|
||||||
<view class="form-item">
|
|
||||||
<text class="label">密码</text>
|
|
||||||
<input class="input" v-model="form.password" placeholder="请输入密码" password />
|
|
||||||
</view>
|
|
||||||
<button class="btn-fallback" @click="handleFallbackLogin" :disabled="loading">
|
|
||||||
{{ loading ? '登录中...' : '账号密码登录' }}
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
<button class="btn-toggle" v-if="!showFallback" @click="showFallback = true">
|
|
||||||
使用账号密码登录
|
|
||||||
</button>
|
|
||||||
<!-- #endif -->
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="agreement">
|
<view class="agreement">
|
||||||
@@ -49,18 +25,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { useUserStore } from '../../store/user'
|
import { useUserStore } from '../../store/user'
|
||||||
import { showToast } from '../../utils'
|
import { showToast } from '../../utils'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const showFallback = ref(false)
|
|
||||||
|
|
||||||
const form = reactive({
|
|
||||||
username: '',
|
|
||||||
password: ''
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 微信手机号授权回调 → 登录 */
|
/** 微信手机号授权回调 → 登录 */
|
||||||
async function handleGetPhoneNumber(e: any) {
|
async function handleGetPhoneNumber(e: any) {
|
||||||
@@ -104,26 +74,6 @@ async function handleGetPhoneNumber(e: any) {
|
|||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 账号密码登录(降级方案 / H5 用) */
|
|
||||||
async function handleFallbackLogin() {
|
|
||||||
if (!form.username || !form.password) {
|
|
||||||
showToast('请输入账号和密码')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
await userStore.login({ username: form.username, password: form.password })
|
|
||||||
showToast('登录成功', 'success')
|
|
||||||
setTimeout(() => {
|
|
||||||
uni.switchTab({ url: '/pages/index/index' })
|
|
||||||
}, 1000)
|
|
||||||
} catch (err: any) {
|
|
||||||
console.error('登录失败:', err)
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@@ -181,62 +131,6 @@ async function handleFallbackLogin() {
|
|||||||
background: #9ED6B5;
|
background: #9ED6B5;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form {
|
|
||||||
margin-top: 40rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-item {
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
display: block;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 12rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
width: 100%;
|
|
||||||
height: 80rpx;
|
|
||||||
padding: 0 24rpx;
|
|
||||||
background: #f5f5f5;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
font-size: 28rpx;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-fallback {
|
|
||||||
width: 100%;
|
|
||||||
height: 88rpx;
|
|
||||||
line-height: 88rpx;
|
|
||||||
background: #4A90D9;
|
|
||||||
color: #fff;
|
|
||||||
border-radius: 44rpx;
|
|
||||||
font-size: 30rpx;
|
|
||||||
margin-top: 20rpx;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-toggle {
|
|
||||||
width: 100%;
|
|
||||||
height: 88rpx;
|
|
||||||
line-height: 88rpx;
|
|
||||||
background: transparent;
|
|
||||||
color: #4A90D9;
|
|
||||||
border: 2rpx solid #4A90D9;
|
|
||||||
border-radius: 44rpx;
|
|
||||||
font-size: 30rpx;
|
|
||||||
margin-top: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.h5-tip {
|
|
||||||
text-align: center;
|
|
||||||
padding: 40rpx;
|
|
||||||
color: #999;
|
|
||||||
font-size: 28rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.agreement {
|
.agreement {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useUserStore } from '../../../../store/user'
|
import { useUserStore } from '../../store/user'
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
const defaultAvatar = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
const defaultAvatar = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
||||||
@@ -1,239 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="container">
|
|
||||||
<view class="user-card">
|
|
||||||
<image
|
|
||||||
class="avatar"
|
|
||||||
:src="userStore.userInfo?.avatarUrl || defaultAvatar"
|
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
<view class="user-info">
|
|
||||||
<text class="nickname">{{ userStore.userInfo?.nickname || '未登录' }}</text>
|
|
||||||
<text class="user-id">ID: {{ userStore.userInfo?.id || '---' }}</text>
|
|
||||||
</view>
|
|
||||||
<button v-if="!userStore.isLogin" class="login-btn" size="mini" @click="goLogin">
|
|
||||||
登录
|
|
||||||
</button>
|
|
||||||
<button v-else class="login-btn" size="mini" @click="handleLogout">
|
|
||||||
退出
|
|
||||||
</button>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="section">
|
|
||||||
<view class="section-title">功能菜单</view>
|
|
||||||
|
|
||||||
<view class="menu-list">
|
|
||||||
<view class="menu-item" @click="goToLogs">
|
|
||||||
<view class="menu-icon">📝</view>
|
|
||||||
<text class="menu-text">查看日志</text>
|
|
||||||
<view class="menu-arrow">›</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="menu-item" @click="showAbout">
|
|
||||||
<view class="menu-icon">ℹ️</view>
|
|
||||||
<text class="menu-text">关于应用</text>
|
|
||||||
<view class="menu-arrow">›</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="menu-item" @click="clearCache">
|
|
||||||
<view class="menu-icon">🗑️</view>
|
|
||||||
<text class="menu-text">清除缓存</text>
|
|
||||||
<view class="menu-arrow">›</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view class="section">
|
|
||||||
<view class="section-title">技术栈</view>
|
|
||||||
<view class="tech-list">
|
|
||||||
<view class="tech-item">
|
|
||||||
<text class="tech-label">框架</text>
|
|
||||||
<text class="tech-value">uni-app</text>
|
|
||||||
</view>
|
|
||||||
<view class="tech-item">
|
|
||||||
<text class="tech-label">Vue</text>
|
|
||||||
<text class="tech-value">3.x</text>
|
|
||||||
</view>
|
|
||||||
<view class="tech-item">
|
|
||||||
<text class="tech-label">构建</text>
|
|
||||||
<text class="tech-value">Vite</text>
|
|
||||||
</view>
|
|
||||||
<view class="tech-item">
|
|
||||||
<text class="tech-label">语言</text>
|
|
||||||
<text class="tech-value">TypeScript</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useUserStore } from '../../store/user'
|
|
||||||
import { showToast } from '../../utils'
|
|
||||||
|
|
||||||
const userStore = useUserStore()
|
|
||||||
const defaultAvatar = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
|
||||||
|
|
||||||
function goLogin() {
|
|
||||||
uni.navigateTo({ url: '/pages/login/login' })
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleLogout() {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '确定要退出登录吗?',
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
userStore.logout()
|
|
||||||
showToast('已退出登录', 'success')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function goToLogs() {
|
|
||||||
uni.navigateTo({ url: '/pages/logs/logs' })
|
|
||||||
}
|
|
||||||
|
|
||||||
function showAbout() {
|
|
||||||
uni.showModal({
|
|
||||||
title: '关于',
|
|
||||||
content: 'zhy-test uni-app 项目\n\n支持多端发布:\n- 微信小程序\n- H5\n- Android/iOS App',
|
|
||||||
showCancel: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearCache() {
|
|
||||||
uni.showModal({
|
|
||||||
title: '提示',
|
|
||||||
content: '确定要清除缓存吗?',
|
|
||||||
success: (res) => {
|
|
||||||
if (res.confirm) {
|
|
||||||
uni.clearStorageSync()
|
|
||||||
showToast('缓存已清除', 'success')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.container {
|
|
||||||
min-height: 100vh;
|
|
||||||
padding: 30rpx;
|
|
||||||
box-sizing: border-box;
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-card {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
padding: 40rpx;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar {
|
|
||||||
width: 120rpx;
|
|
||||||
height: 120rpx;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-info {
|
|
||||||
flex: 1;
|
|
||||||
margin-left: 30rpx;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nickname {
|
|
||||||
font-size: 32rpx;
|
|
||||||
color: #333;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-id {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.login-btn {
|
|
||||||
font-size: 26rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 20rpx;
|
|
||||||
padding: 30rpx;
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #666;
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-list {
|
|
||||||
border-radius: 12rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 24rpx 0;
|
|
||||||
border-bottom: 1rpx solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-item:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-icon {
|
|
||||||
font-size: 36rpx;
|
|
||||||
margin-right: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-text {
|
|
||||||
flex: 1;
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.menu-arrow {
|
|
||||||
font-size: 36rpx;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-list {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
gap: 20rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-item {
|
|
||||||
width: calc(50% - 10rpx);
|
|
||||||
background: #f8f8f8;
|
|
||||||
padding: 20rpx;
|
|
||||||
border-radius: 12rpx;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-label {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tech-value {
|
|
||||||
font-size: 28rpx;
|
|
||||||
color: #333;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
import { defineStore } from 'pinia'
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import * as cardApi from '../api/card'
|
|
||||||
import type { CardInfo, CardDetail, MyCard, ActivateParams, QrCodeInfo } from '../api/types'
|
|
||||||
|
|
||||||
export const useCardStore = defineStore('card', () => {
|
|
||||||
const cardList = ref<CardInfo[]>([])
|
|
||||||
const currentCard = ref<CardDetail | null>(null)
|
|
||||||
const myCards = ref<MyCard[]>([])
|
|
||||||
const loading = ref(false)
|
|
||||||
|
|
||||||
/** 获取年卡列表 */
|
|
||||||
async function fetchCardList(params?: { keyword?: string; category?: string }) {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
cardList.value = await cardApi.getCardList(params)
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取年卡详情 */
|
|
||||||
async function fetchCardDetail(id: string) {
|
|
||||||
loading.value = true
|
|
||||||
try {
|
|
||||||
currentCard.value = await cardApi.getCardDetail(id)
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取我的年卡 */
|
|
||||||
async function fetchMyCards() {
|
|
||||||
myCards.value = await cardApi.getMyCards()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 激活年卡 */
|
|
||||||
async function activateCard(cardId: string, data: ActivateParams) {
|
|
||||||
return await cardApi.activateCard(cardId, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 绑定年卡 */
|
|
||||||
async function bindCard(cardNo: string) {
|
|
||||||
return await cardApi.bindCard(cardNo)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取入园码 */
|
|
||||||
async function getEntryQrCode(cardId: string): Promise<QrCodeInfo> {
|
|
||||||
return await cardApi.getEntryQrCode(cardId)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
cardList,
|
|
||||||
currentCard,
|
|
||||||
myCards,
|
|
||||||
loading,
|
|
||||||
fetchCardList,
|
|
||||||
fetchCardDetail,
|
|
||||||
fetchMyCards,
|
|
||||||
activateCard,
|
|
||||||
bindCard,
|
|
||||||
getEntryQrCode
|
|
||||||
}
|
|
||||||
})
|
|
||||||
+2
-13
@@ -1,8 +1,8 @@
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { getToken, setToken, removeToken } from '../api/request'
|
import { getToken, setToken, removeToken } from '../api/request'
|
||||||
import { wxLogin as apiWxLogin, login as apiLogin, getUserInfo as apiGetUserInfo } from '../api/user'
|
import { wxLogin as apiWxLogin, getUserInfo as apiGetUserInfo } from '../api/user'
|
||||||
import type { UserInfo, LoginParams } from '../api/types'
|
import type { UserInfo } from '../api/types'
|
||||||
import { TOKEN_KEY, REFRESH_TOKEN_KEY } from '../config'
|
import { TOKEN_KEY, REFRESH_TOKEN_KEY } from '../config'
|
||||||
|
|
||||||
export const useUserStore = defineStore('user', () => {
|
export const useUserStore = defineStore('user', () => {
|
||||||
@@ -22,16 +22,6 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 账号密码登录(降级方案) */
|
|
||||||
async function login(params: LoginParams) {
|
|
||||||
const result = await apiLogin(params)
|
|
||||||
token.value = result.accessToken
|
|
||||||
refreshToken.value = result.refreshToken
|
|
||||||
setToken(result.accessToken)
|
|
||||||
uni.setStorageSync(REFRESH_TOKEN_KEY, result.refreshToken)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取用户信息 */
|
/** 获取用户信息 */
|
||||||
async function fetchUserInfo() {
|
async function fetchUserInfo() {
|
||||||
if (!token.value) return
|
if (!token.value) return
|
||||||
@@ -55,7 +45,6 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
userInfo,
|
userInfo,
|
||||||
isLogin,
|
isLogin,
|
||||||
wxLogin,
|
wxLogin,
|
||||||
login,
|
|
||||||
fetchUserInfo,
|
fetchUserInfo,
|
||||||
logout
|
logout
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
const formatTime = date => {
|
|
||||||
const year = date.getFullYear()
|
|
||||||
const month = date.getMonth() + 1
|
|
||||||
const day = date.getDate()
|
|
||||||
const hour = date.getHours()
|
|
||||||
const minute = date.getMinutes()
|
|
||||||
const second = date.getSeconds()
|
|
||||||
|
|
||||||
return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatNumber = n => {
|
|
||||||
n = n.toString()
|
|
||||||
return n[1] ? n : `0${n}`
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
formatTime
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user