- fix manual bind stuck at BLE scan, redirect to bind-success - add 15s timeout and stopScan to ble-connect - add stopScan method to ble.js - add back-to-home button on bind-success page - fix field name in subscribe-plans (plan -> plan_type) - fix history.js to handle created_at field - fix index.js to handle device name field - add subscription route alias in request.js - extend admin cloud function from 1 to 9 actions - add mock mode to admin-console request.js - remove unused discover page and legacy record function Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
185 行
6.6 KiB
JavaScript
185 行
6.6 KiB
JavaScript
const cloud = require('wx-server-sdk')
|
|
cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV })
|
|
const db = cloud.database()
|
|
const _ = db.command
|
|
const PAGE_SIZE = 20
|
|
|
|
exports.main = async (event, context) => {
|
|
const { action, data } = event
|
|
|
|
if (action === 'dashboard') {
|
|
const [deviceCount, userCount, treatmentCount, subCount] = await Promise.all([
|
|
db.collection('bindings').where({ status: 'active' }).count(),
|
|
db.collection('users').count(),
|
|
db.collection('treatment_records').count(),
|
|
db.collection('subscriptions').where({ status: 'active' }).count()
|
|
])
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
device_count: deviceCount.total,
|
|
user_count: userCount.total,
|
|
treatment_count: treatmentCount.total,
|
|
subscription_count: subCount.total
|
|
}
|
|
}
|
|
}
|
|
|
|
if (action === 'devices') {
|
|
const { page = 1, page_size = PAGE_SIZE, keyword } = data || {}
|
|
let query = db.collection('bindings')
|
|
const conditions = { status: 'active' }
|
|
if (keyword) {
|
|
conditions.device_id = db.RegExp({ regexp: keyword, options: 'i' })
|
|
}
|
|
query = query.where(conditions)
|
|
const [totalRes, records] = await Promise.all([
|
|
query.count(),
|
|
query.orderBy('bind_time', 'desc').skip((page - 1) * page_size).limit(page_size).get()
|
|
])
|
|
const devices = records.data.map(b => ({
|
|
device_id: b.device_id,
|
|
bound_user: b.openid ? b.openid.slice(-8) : '-',
|
|
battery: null,
|
|
fw_version: '1.0.0',
|
|
activated_at: b.bind_time,
|
|
status: 2
|
|
}))
|
|
return { code: 0, data: { records: devices, total: totalRes.total } }
|
|
}
|
|
|
|
if (action === 'device_detail') {
|
|
const { device_id } = data
|
|
const bindings = await db.collection('bindings').where({ device_id, status: 'active' }).get()
|
|
if (bindings.data.length === 0) return { code: -1, message: '设备不存在' }
|
|
const b = bindings.data[0]
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
device_id: b.device_id,
|
|
bound_user: b.openid ? b.openid.slice(-8) : '-',
|
|
battery: null,
|
|
fw_version: '1.0.0',
|
|
activated_at: b.bind_time,
|
|
status: 2
|
|
}
|
|
}
|
|
}
|
|
|
|
if (action === 'device_unbind') {
|
|
const { device_id } = data
|
|
await db.collection('bindings').where({ device_id, status: 'active' }).update({
|
|
data: { status: 'inactive', unbind_time: db.serverDate() }
|
|
})
|
|
return { code: 0, data: {} }
|
|
}
|
|
|
|
if (action === 'users') {
|
|
const { page = 1, page_size = PAGE_SIZE, keyword } = data || {}
|
|
let conditions = {}
|
|
if (keyword) {
|
|
conditions = _.or([
|
|
{ openid: db.RegExp({ regexp: keyword, options: 'i' }) },
|
|
{ nickname: db.RegExp({ regexp: keyword, options: 'i' }) }
|
|
])
|
|
}
|
|
const [totalRes, records] = await Promise.all([
|
|
db.collection('users').where(conditions).count(),
|
|
db.collection('users').where(conditions).orderBy('created_at', 'desc').skip((page - 1) * page_size).limit(page_size).get()
|
|
])
|
|
return { code: 0, data: { records: records.data, total: totalRes.total } }
|
|
}
|
|
|
|
if (action === 'user_detail') {
|
|
const { user_id } = data
|
|
const userRes = await db.collection('users').doc(user_id).get()
|
|
const user = userRes.data
|
|
const [bindings, subs, treatments] = await Promise.all([
|
|
db.collection('bindings').where({ openid: user.openid, status: 'active' }).get(),
|
|
db.collection('subscriptions').where({ openid: user.openid }).orderBy('start_time', 'desc').limit(1).get(),
|
|
db.collection('treatment_records').where({ openid: user.openid }).orderBy('created_at', 'desc').limit(5).get()
|
|
])
|
|
const devices = bindings.data.map(b => ({ device_id: b.device_id, device_name: '我的光面膜' }))
|
|
const sub = subs.data[0] || {}
|
|
const treatmentCount = await db.collection('treatment_records').where({ openid: user.openid }).count()
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
...user,
|
|
user_id: user._id,
|
|
devices,
|
|
subscription_type: sub.plan_type || 'none',
|
|
subscription_status: sub.status || 'none',
|
|
subscription_expire: sub.end_time || null,
|
|
treatment_count: treatmentCount.total,
|
|
recent_treatments: treatments.data
|
|
}
|
|
}
|
|
}
|
|
|
|
if (action === 'subscriptions') {
|
|
const { page = 1, page_size = PAGE_SIZE, tab } = data || {}
|
|
let conditions = {}
|
|
if (tab && tab !== 'all') {
|
|
if (tab === 'expired') {
|
|
conditions = { status: 'expired' }
|
|
} else {
|
|
conditions = { plan_type: tab, status: 'active' }
|
|
}
|
|
}
|
|
const [totalRes, records] = await Promise.all([
|
|
db.collection('subscriptions').where(conditions).count(),
|
|
db.collection('subscriptions').where(conditions).orderBy('start_time', 'desc').skip((page - 1) * page_size).limit(page_size).get()
|
|
])
|
|
const monthlyCount = await db.collection('subscriptions').where({ plan_type: 'monthly', status: 'active' }).count()
|
|
const yearlyCount = await db.collection('subscriptions').where({ plan_type: 'yearly', status: 'active' }).count()
|
|
const trialCount = await db.collection('subscriptions').where({ plan_type: 'trial', status: 'active' }).count()
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
records: records.data.map(s => ({
|
|
...s,
|
|
id: s._id,
|
|
user_id: s.openid ? s.openid.slice(-8) : '-',
|
|
plan: s.plan_type,
|
|
amount: s.price || '-',
|
|
started_at: s.start_time,
|
|
expired_at: s.end_time,
|
|
status: s.status === 'active' ? 1 : 3
|
|
})),
|
|
total: totalRes.total,
|
|
stats: {
|
|
monthly_count: monthlyCount.total,
|
|
yearly_count: yearlyCount.total,
|
|
trial_count: trialCount.total
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (action === 'records') {
|
|
const { page = 1, page_size = PAGE_SIZE, user_id } = data || {}
|
|
let conditions = {}
|
|
if (user_id) {
|
|
const userRes = await db.collection('users').doc(user_id).get()
|
|
conditions = { openid: userRes.data.openid }
|
|
}
|
|
const [totalRes, records] = await Promise.all([
|
|
db.collection('treatment_records').where(conditions).count(),
|
|
db.collection('treatment_records').where(conditions).orderBy('created_at', 'desc').skip((page - 1) * page_size).limit(page_size).get()
|
|
])
|
|
return { code: 0, data: { records: records.data, total: totalRes.total } }
|
|
}
|
|
|
|
if (action === 'logs') {
|
|
const { page = 1, page_size = PAGE_SIZE } = data || {}
|
|
const [totalRes, records] = await Promise.all([
|
|
db.collection('operation_logs').count(),
|
|
db.collection('operation_logs').orderBy('created_at', 'desc').skip((page - 1) * page_size).limit(page_size).get()
|
|
])
|
|
return { code: 0, data: { records: records.data, total: totalRes.total } }
|
|
}
|
|
|
|
return { code: -1, message: '未知操作' }
|
|
}
|