refactor: 确立独立子工程架构 (backend, admin, mpuniapp) 并同步更新 AGENTS.md 规范

这个提交包含在:
wikiboss
2026-09-20 17:05:22 +08:00
父节点 de3cf8b870
当前提交 9fa1d1fbd0
共有 1679 个文件被更改,包括 204798 次插入 和 16817 次删除

查看文件

@@ -0,0 +1,146 @@
<template>
<!-- #ifdef APP -->
<scroll-view style="flex: 1;padding: 6px;">
<!-- #endif -->
<text class="uni-h2">加速度计</text>
<text>开始监听后可实时查看设备在 X、Y、Z 轴上的加速度数据。</text>
<text class="margin-v">当前状态:{{ statusText }}</text>
<text class="uni-h3">采样频率</text>
<radio-group class="option-group" @change="handleIntervalChange">
<view class="option-item" v-for="item in intervalOptions" :key="item.value">
<radio :value="item.value" :checked="activeInterval == item.value">
<text class="option-text">{{ item.label }}</text>
</radio>
</view>
</radio-group>
<button class="margin-v" type="primary" @tap="startListen">开始监听</button>
<button class="margin-v" @tap="stopListen">停止监听</button>
<button class="margin-v" @tap="navigateToShake">跳转摇一摇</button>
<text class="uni-h3">实时数据</text>
<view class="log-list">
<text class="log-item" v-for="item in axisItems" :key="item.key">{{ item.key }}:{{ item.value }}</text>
</view>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
type PageAccelerometerInterval = 'game' | 'ui' | 'normal'
type IntervalOption = {
value : PageAccelerometerInterval
label : string
}
type AxisItem = {
key : string
value : string
}
const intervalOptions : IntervalOption[] = [
{ value: 'normal', label: 'normal' },
{ value: 'ui', label: 'ui' },
{ value: 'game', label: 'game' }
]
const activeInterval = ref<PageAccelerometerInterval>('normal')
const statusText = ref('未启动')
const axisX = ref('0.000')
const axisY = ref('0.000')
const axisZ = ref('0.000')
const axisItems = computed((): AxisItem[] => {
return [
{ key: 'X', value: axisX.value },
{ key: 'Y', value: axisY.value },
{ key: 'Z', value: axisZ.value }
]
})
function formatAxisValue(value : number) : string {
return value.toFixed(3)
}
const accelerometerListener : OnAccelerometerChangeCallback = (result : OnAccelerometerChangeCallbackResult) => {
axisX.value = formatAxisValue(result.x)
axisY.value = formatAxisValue(result.y)
axisZ.value = formatAxisValue(result.z)
}
function handleIntervalChange(event : UniRadioGroupChangeEvent) : void {
activeInterval.value = event.detail.value as PageAccelerometerInterval
}
function startListen() : void {
uni.onAccelerometerChange(accelerometerListener)
uni.startAccelerometer({
interval: activeInterval.value,
success: () => {
statusText.value = `监听中 (${activeInterval.value})`
},
fail: (error) => {
statusText.value = error.errMsg != null ? error.errMsg : '启动失败'
console.error('startAccelerometer:fail', error)
}
})
}
function stopListen() : void {
uni.stopAccelerometer({
success: () => {
statusText.value = '已停止'
}
})
}
function navigateToShake() : void {
uni.navigateTo({
url: '/pages/API/accelerometer/shake'
})
}
onUnload(() => {
uni.offAccelerometerChange(accelerometerListener)
uni.stopAccelerometer()
})
</script>
<style>
.margin-v {
margin: 5px 0;
}
.option-group {
margin: 5px 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.option-item {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 18px;
margin-top: 8px;
}
.option-text {
font-size: 14px;
}
.log-list {
margin: 5px 0;
padding: 10px;
border: 1px solid #ccc;
display: flex;
flex-direction: column;
}
.log-item {
font-size: 14px;
margin: 4px 0;
}
</style>

查看文件

@@ -0,0 +1,198 @@
<template>
<!-- #ifdef APP -->
<scroll-view style="flex:1;padding: 6px;">
<!-- #endif -->
<text class="uni-h3">摇一摇</text>
<text>握住手机并快速摇晃,会调用加速计传感器,依据加速度变化检测动作,并弹出提示。</text>
<text class="log-text margin-v">{{ statusText }}</text>
<view class="uni-row margin-v">
<view class="metric-box">
<text>瞬时变化</text>
<text class="metric-value">{{ deltaText }}</text>
</view>
<view class="metric-box metric-box-space">
<text>触发次数</text>
<text class="metric-value">{{ shakeCountText }}</text>
</view>
</view>
<view class="sensitivity-header">
<text>灵敏度</text>
<text class="sensitivity-value">{{ sensitivityLabel }}</text>
</view>
<slider class="sensitivity-slider" :value="sensitivityValue" :min="1" :max="5" :step="1"
@changing="onSensitivityChanging" @change="onSensitivityChange" />
<text class="sensitivity-tip">当前触发阈值:{{ thresholdText }},数值越低灵敏度越高,越容易触发。</text>
<!-- #ifdef APP -->
</scroll-view>
<!-- #endif -->
</template>
<script setup lang="uts">
const statusText = ref('正在初始化传感器...')
const deltaText = ref('0.00')
const shakeCountText = ref('0')
const thresholdText = ref('1.35')
const sensitivityLabel = ref('中')
const sensitivityValue = ref(3)
const shakeCooldown = 1200
let lastMagnitude : number | null = null
let lastShakeTime = 0
let shakeCount = 0
let shakeThreshold = 1.35
function formatNumber(value : number) : string {
return value.toFixed(2)
}
function createMagnitude(x : number, y : number, z : number) : number {
return Math.sqrt(x * x + y * y + z * z)
}
function getSensitivityLabel(value : number) : string {
if (value <= 1) {
return '很低'
}
if (value == 2) {
return '较低'
}
if (value == 3) {
return '中'
}
if (value == 4) {
return '较高'
}
return '很高'
}
function syncSensitivity(value : number) : void {
sensitivityValue.value = value
shakeThreshold = 2.1 - value * 0.25
thresholdText.value = formatNumber(shakeThreshold)
sensitivityLabel.value = getSensitivityLabel(value)
}
function triggerShake(now : number) : void {
lastShakeTime = now
shakeCount = shakeCount + 1
shakeCountText.value = `${shakeCount}`
statusText.value = '检测成功,继续摇晃可再次触发'
uni.showToast({
title: '检测到摇一摇',
icon: 'none'
})
}
const accelerometerListener : OnAccelerometerChangeCallback = (result : OnAccelerometerChangeCallbackResult) => {
const magnitude = createMagnitude(result.x, result.y, result.z)
if (lastMagnitude == null) {
lastMagnitude = magnitude
statusText.value = '请开始摇晃手机'
return
}
const delta = Math.abs(magnitude - (lastMagnitude as number))
deltaText.value = formatNumber(delta)
lastMagnitude = magnitude
const now = Date.now()
const passed = now - lastShakeTime
if (delta > shakeThreshold && passed > shakeCooldown) {
triggerShake(now)
}
}
function onSensitivityChanging(event : UniSliderChangeEvent) : void {
syncSensitivity(event.detail.value)
}
function onSensitivityChange(event : UniSliderChangeEvent) : void {
syncSensitivity(event.detail.value)
statusText.value = `当前灵敏度:${sensitivityLabel.value},请继续摇晃手机`
}
function startListen() : void {
uni.startAccelerometer({
interval: 'game',
success: () => {
statusText.value = '请开始摇晃手机'
},
fail: (error) => {
statusText.value = error.errMsg != null ? error.errMsg : '传感器启动失败'
}
})
}
function stopListen() : void {
uni.stopAccelerometer({
success: () => {
statusText.value = '已停止监听'
}
})
}
onReady(() => {
syncSensitivity(sensitivityValue.value)
uni.onAccelerometerChange(accelerometerListener)
startListen()
})
onShow(() => {
startListen()
})
onHide(() => {
stopListen()
})
onUnload(() => {
uni.offAccelerometerChange(accelerometerListener)
uni.stopAccelerometer()
})
</script>
<style>
.card-space {
margin: 5px;
}
.margin-v {
margin: 5px 0;
}
.log-text {
padding: 10px;
font-size: 14px;
border: 1px solid #ccc;
}
.metric-box {
flex: 1;
padding: 14px;
}
.metric-box-space {
margin-left: 10px;
}
.metric-value {
margin-top: 4px;
font-size: 30px;
}
.sensitivity-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.sensitivity-slider {
margin: 15px;
}
</style>