feat: init project with miniprogram, cloud functions and admin console

这个提交包含在:
Guoguo
2026-04-22 21:24:20 +08:00
当前提交 a84e37a6e2
修改 106 个文件,包含 5902 行新增0 行删除
@@ -0,0 +1,165 @@
<template>
<view class="container">
<view class="toolbar flex-between">
<text class="total-text"> {{ total }} </text>
<u-button type="primary" size="small" @click="showCreate = true">创建订阅</u-button>
</view>
<view class="table-wrap">
<u-table>
<u-tr>
<u-th>用户ID</u-th>
<u-th>昵称</u-th>
<u-th>类型</u-th>
<u-th>方案</u-th>
<u-th>状态</u-th>
<u-th>到期时间</u-th>
</u-tr>
<u-tr v-for="item in subscriptions" :key="item.id">
<u-td>{{ item.user_id }}</u-td>
<u-td>{{ item.nickname || '-' }}</u-td>
<u-td>{{ subTypeMap[item.type] || '-' }}</u-td>
<u-td>{{ item.plan || '-' }}</u-td>
<u-td>
<text :class="item.status === 1 ? 'text-success' : 'text-muted'">
{{ subStatusMap[item.status] || '-' }}
</text>
</u-td>
<u-td>{{ formatDate(item.expired_at) }}</u-td>
</u-tr>
</u-table>
</view>
<view class="pagination">
<u-button size="small" :disabled="page <= 1" @click="onPage(page - 1)">上一页</u-button>
<text class="page-info"> {{ page }} / {{ totalPages }} </text>
<u-button size="small" :disabled="page >= totalPages" @click="onPage(page + 1)">下一页</u-button>
</view>
<u-popup :show="showCreate" @close="showCreate = false" mode="center">
<view class="create-form">
<view class="form-title">创建订阅</view>
<u-form :model="createForm">
<u-form-item label="用户ID">
<u-input v-model="createForm.user_id" placeholder="输入用户ID" />
</u-form-item>
<u-form-item label="方案">
<u-input v-model="createForm.plan" placeholder="monthly/quarterly/yearly" />
</u-form-item>
<u-form-item label="天数">
<u-input v-model="createForm.days" placeholder="订阅天数" type="number" />
</u-form-item>
</u-form>
<u-button type="primary" @click="onCreate" :loading="creating">创建</u-button>
</view>
</u-popup>
</view>
</template>
<script>
import { get, post } from '../../utils/request'
export default {
data() {
return {
subscriptions: [],
total: 0,
page: 1,
pageSize: 20,
showCreate: false,
creating: false,
createForm: { user_id: '', plan: 'monthly', days: 30 },
subTypeMap: { 1: '试用', 2: '正式', 3: '赠送' },
subStatusMap: { 1: '有效', 2: '已过期', 3: '已停用' }
}
},
computed: {
totalPages() {
return Math.ceil(this.total / this.pageSize) || 1
}
},
onShow() {
this.loadSubscriptions()
},
methods: {
async loadSubscriptions() {
try {
const data = await get('/api/v1/admin/subscriptions', { page: this.page, page_size: this.pageSize })
this.subscriptions = data.records || []
this.total = data.total || 0
} catch (e) {}
},
onPage(p) {
this.page = p
this.loadSubscriptions()
},
async onCreate() {
this.creating = true
try {
await post('/api/v1/admin/subscriptions', {
user_id: parseInt(this.createForm.user_id),
plan: this.createForm.plan,
days: parseInt(this.createForm.days)
})
this.showCreate = false
this.loadSubscriptions()
uni.showToast({ title: '创建成功', icon: 'success' })
} catch (e) {
uni.showToast({ title: '创建失败', icon: 'none' })
} finally {
this.creating = false
}
},
formatDate(d) {
return d ? d.slice(0, 10) : '-'
}
}
}
</script>
<style scoped>
.container {
padding: 16px;
}
.toolbar {
margin-bottom: 16px;
}
.total-text {
font-size: 13px;
color: #999999;
}
.pagination {
display: flex;
align-items: center;
justify-content: center;
gap: 16px;
margin-top: 16px;
}
.page-info {
font-size: 13px;
color: #999999;
}
.create-form {
padding: 24px;
width: 400px;
}
.form-title {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
}
.text-success {
color: #52c41a;
}
.text-muted {
color: #999999;
}
</style>