fix: improve UX and fix admin console display issues

Miniprogram:
- Add back buttons to all custom-nav pages
- Add debug/mock buttons (BLE connect, wear check, treatment)
  controlled by __DEV__ flag (hidden in prod)

Admin console:
- Fix log page using nonexistent fields (operator_type, target_type)
  now correctly reads admin_id/user_id/action/detail from API
- Fix subscription date fields (started_at→start_time, expired_at→expire_time)
- Wire up subscription detail/extend/renew action buttons
- Wire up device detail "查看完整日志" button
- Add "创建订阅" button to subscription toolbar
- Fix subscription status mapping (2=expired, 3=cancelled)

Docs:
- Add detailed architecture docs for server, miniprogram, admin console
这个提交包含在:
Guoguo
2026-04-28 18:32:26 -07:00
父节点 91d5937d8e
当前提交 c5f6033ccf
修改 30 个文件,包含 1509 行新增59 行删除
+36 -38
查看文件
@@ -15,15 +15,15 @@
<view class="page-card">
<view class="log-list">
<view class="log-item" v-for="item in logs" :key="item.id">
<view class="log-item" v-for="item in logs" :key="item.log_id">
<text class="log-time">{{ formatDate(item.created_at) }}</text>
<view class="log-content">
<text :class="logTypeBadge(item.operator_type)">{{ logTypeText(item.operator_type) }}</text>
<text :class="actorBadge(item)">{{ actorLabel(item) }}</text>
<text class="log-text">
<text class="log-actor" :class="logActorClass(item.operator_type)">{{ item.operator_type === 1 ? '管理员' : '系统' }}</text>
<text class="log-target">{{ item.target_type }} {{ item.target_id || '' }}</text>
执行了 <text class="log-action">{{ item.action }}</text>
<text class="log-action">{{ actionLabel(item.action) }}</text>
<text class="log-detail" v-if="item.detail"> {{ item.detail }}</text>
</text>
<text class="log-meta" v-if="item.ip">IP: {{ item.ip }}</text>
</view>
</view>
</view>
@@ -60,6 +60,11 @@ export default {
return Math.ceil(this.total / this.pageSize) || 1
}
},
onLoad(options) {
if (options && options.device_id) {
this.filters.device_id = options.device_id
}
},
onShow() {
this.loadLogs()
},
@@ -84,20 +89,24 @@ export default {
this.page = p
this.loadLogs()
},
logTypeText(type) {
if (type === 1) return '管理操作'
if (type === 2) return '系统事件'
return '用户操作'
actorLabel(item) {
if (item.admin_id) return '管理员 #' + item.admin_id
if (item.user_id) return '用户 #' + item.user_id
return '系统'
},
logTypeBadge(type) {
if (type === 1) return 'badge badge-pink'
if (type === 2) return 'badge badge-blue'
return 'badge badge-green'
actorBadge(item) {
if (item.admin_id) return 'badge badge-pink'
if (item.user_id) return 'badge badge-green'
return 'badge badge-blue'
},
logActorClass(type) {
if (type === 1) return 'actor-admin'
if (type === 2) return 'actor-system'
return 'actor-user'
actionLabel(action) {
var map = {
admin_login: '管理员登录', admin_device_create: '创建设备', admin_device_unbind: '后台解绑',
admin_device_command: '下发指令', user_register: '用户注册', user_login: '用户登录',
device_bind: '设备绑定', device_unbind: '设备解绑', treatment_sync: '护理记录同步',
subscription_verify: '订阅核销'
}
return map[action] || action
},
formatDate: formatDateUtil,
async onExport() {
@@ -170,29 +179,18 @@ export default {
color: #666;
}
.log-actor {
font-weight: 600;
}
.actor-admin {
color: #E6508C;
}
.actor-system {
color: #1890ff;
}
.actor-user {
color: #52c41a;
}
.log-target {
color: #333;
font-weight: 500;
}
.log-action {
color: #333;
font-weight: 500;
}
.log-detail {
color: #999;
}
.log-meta {
font-size: 12px;
color: #bbb;
margin-top: 2px;
}
</style>