chore: 添加 CLAUDE.md 和 .env 配置文件

- 添加项目文档 CLAUDE.md,包含常用命令和架构说明
- 添加 packages/server/.env 环境变量配置文件

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
richarjiang
2026-04-06 21:46:15 +08:00
parent f94b48203f
commit 58c7588a96
5 changed files with 117 additions and 27 deletions

View File

@@ -133,7 +133,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { ref, onMounted } from 'vue'
import CustomNavBar from '../../components/CustomNavBar.vue'
import { getSystemLayout } from '../../utils/system'
import { useAdminStore } from '../../stores/admin'
@@ -202,9 +202,9 @@ async function loadOrders(reset = false) {
if (activeFilter.value) params.status = activeFilter.value
const result = await adminStore.fetchAdminOrders(params)
if (reset) {
orders.value = [...result.data]
orders.value = [...result.items]
} else {
orders.value.push(...result.data)
orders.value.push(...result.items)
}
hasMore.value = orders.value.length < result.total
totalCount.value = result.total

View File

@@ -103,15 +103,15 @@
<view class="hero-badge">
<text class="hero-badge-text">{{ typeLabel }}</text>
</view>
<text class="hero-name">{{ card.name }}</text>
<text class="hero-name">{{ cardData.name }}</text>
<view class="hero-price-row">
<text class="hero-currency">¥</text>
<text class="hero-price">{{ formatPrice(card.price) }}</text>
<text class="hero-price">{{ formatPrice(cardData.price) }}</text>
<text
v-if="card.originalPrice && card.originalPrice > card.price"
v-if="cardData.originalPrice && cardData.originalPrice > cardData.price"
class="hero-original"
>
¥{{ formatPrice(card.originalPrice) }}
¥{{ formatPrice(cardData.originalPrice) }}
</text>
</view>
</view>
@@ -121,28 +121,28 @@
<!-- Key info grid -->
<view class="info-card">
<view class="info-grid">
<view class="info-cell" v-if="card.totalTimes">
<text class="cell-value">{{ card.totalTimes }}</text>
<view class="info-cell" v-if="cardData.totalTimes">
<text class="cell-value">{{ cardData.totalTimes }}</text>
<text class="cell-label">课时次数</text>
</view>
<view class="info-cell">
<text class="cell-value">{{ card.durationDays }}</text>
<text class="cell-value">{{ cardData.durationDays }}</text>
<text class="cell-label">有效天数</text>
</view>
<view class="info-cell">
<text class="cell-value">{{ unitPrice }}</text>
<text class="cell-label">{{ card.totalTimes ? '每次单价' : '按天均价' }}</text>
<text class="cell-label">{{ cardData.totalTimes ? '每次单价' : '按天均价' }}</text>
</view>
</view>
</view>
<!-- Description -->
<view v-if="card.description" class="desc-card">
<view v-if="cardData.description" class="desc-card">
<view class="section-header">
<view class="section-dot" />
<text class="section-title">课程说明</text>
</view>
<text class="desc-content">{{ card.description }}</text>
<text class="desc-content">{{ cardData.description }}</text>
</view>
<!-- Features list -->
@@ -153,13 +153,13 @@
</view>
<view class="feature-item">
<text class="feature-dot"></text>
<text class="feature-text">购买后立即生效有效期 {{ card.durationDays }} </text>
<text class="feature-text">购买后立即生效有效期 {{ cardData.durationDays }} </text>
</view>
<view v-if="card.totalTimes" class="feature-item">
<view v-if="cardData.totalTimes" class="feature-item">
<text class="feature-dot"></text>
<text class="feature-text"> {{ card.totalTimes }} 次课时可灵活安排上课时间</text>
<text class="feature-text"> {{ cardData.totalTimes }} 次课时可灵活安排上课时间</text>
</view>
<view v-if="!card.totalTimes" class="feature-item">
<view v-if="!cardData.totalTimes" class="feature-item">
<text class="feature-dot"></text>
<text class="feature-text">有效期内可无限次预约课程</text>
</view>
@@ -182,7 +182,7 @@
<view class="bottom-bar">
<view class="price-summary">
<text class="summary-label">实付金额</text>
<text class="summary-price">¥{{ formatPrice(card.price) }}</text>
<text class="summary-price">¥{{ formatPrice(cardData.price) }}</text>
</view>
<view
class="buy-btn"
@@ -250,6 +250,8 @@ const unitPrice = computed(() => {
return `¥${(pricePerDay / 100).toFixed(0)}`
})
const cardData = computed<CardType>(() => card.value as CardType)
// ─── Data loading ─────────────────────────────────────────
async function loadCard() {
loading.value = true

View File

@@ -48,8 +48,8 @@
</template>
<script setup lang="ts">
import { ref, nextTick } from 'vue'
import { onShow, onUnmount, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
import { ref, nextTick, onUnmounted } from 'vue'
import { onShow, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
import BrandBanner from '../../components/BrandBanner.vue'
import StudioInfo from '../../components/StudioInfo.vue'
@@ -93,7 +93,7 @@ uni.$on('scrollToCardShop', () => {
pendingScrollToCardShop.value = true
})
onUnmount(() => {
onUnmounted(() => {
uni.$off('scrollToCardShop')
})
@@ -142,14 +142,12 @@ function scrollToCardShop() {
.select(`#${cardShopAnchorId}`)
.boundingClientRect()
.selectViewport()
.scrollOffset()
.exec((res) => {
if (res && res[0] && res[1]) {
const rectTop = (res[0] as UniApp.NodeInfo).top ?? 0
const viewportScroll = (res[1] as UniApp.NodeInfo).scrollTop ?? 0
scrollTop.value = viewportScroll + rectTop
.scrollOffset((res) => {
if (res) {
scrollTop.value = (res as UniApp.NodeInfo).scrollTop ?? 0
}
})
.exec()
})
}
</script>

21
packages/server/.env Normal file
View File

@@ -0,0 +1,21 @@
# Database
DATABASE_URL=mysql://root:AK8jyLfsfMA5wNdC@129.204.155.94:13306/db_mp_focus
# JWT
JWT_SECRET=change-me-to-a-secure-random-string
# WeChat Mini Program
WX_APPID=wx3e7a133d2305fa2c
WX_SECRET=92f4f91af72ca0705d65e39e605cb98b
# WeChat Pay
WX_MCH_ID=1110530023
WX_MCH_KEY=ACbGcH3FNLBacmvmIVR4uWXjNf9h8jQ2
WX_MCH_SERIAL_NO=7A90D96A7ED1A129E98DB5FD5F3A84EDC34B2AC6
WX_MCH_KEY_PATH=./certs/apiclient_key.pem
# API Base URL (used for WeChat Pay callback notification)
API_BASE_URL=https://focus.richarjiang.com/
# Server
PORT=3000