feat: 全系统优化 — 并发控制 + 冗余清理 + 数据流修复 + 全面测试
核心修复: - 状态机加 SELECT FOR UPDATE 行锁,消除并发竞态 - hss_md_staff 加 role 列,登录从数据库读取真实角色 - 申请重复校验排除自身,全流程 20 步闭环通过 - 派单 SQL 修复 + 支付状态机过渡 + 完成服务 plan_item_id 修复 并发控制新增: - RedisLockService (SET NX PX + Lua 安全解锁) - RateLimiterService (Redis 滑动窗口 + API 拦截器) - TransactionIsolationConfig (SERIALIZABLE for 支付回调) - MqttPublisher (异步队列 + JDK TCP 探测) - ObjectStorageService (AWS SigV4 预签名, 纯 JDK) 冗余清理: - 删除 6 个死代码文件 (~620 行) - hutool-all → JDK MessageDigest, 去 MapStruct, 去 jsr310 - haversine 提取到 GeoUtil, count/round 提取到 JdbcUtil - 创建 platform layout 组件 前端修复: - 登录页移除角色选择器, 由后端 JWT 返回 - 移除 ClientOnly 包裹, 页面正常渲染 - SPA fallback Nginx 配置修复 Docker: 运行时镜像 eclipse-temurin:17-jre-jammy (缩小 ~300MB) 文档: 新增系统实现与修复报告.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,22 +1,36 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({ ssr: false })
|
||||
import { ref } from 'vue'
|
||||
import { usePlatformAuth } from '~/composables/usePlatformAuth'
|
||||
const { login, PRESET_USERS } = usePlatformAuth()
|
||||
const selected = ref('admin')
|
||||
const { setAuth } = usePlatformAuth()
|
||||
|
||||
const mode = ref<'login'|'register'>('login')
|
||||
const phone = ref('')
|
||||
const password = ref('')
|
||||
const name = ref('')
|
||||
const loading = ref(false)
|
||||
const error = ref('')
|
||||
const msg = ref('')
|
||||
|
||||
async function doLogin() {
|
||||
loading.value = true; error.value = ''
|
||||
const u = login(selected.value)
|
||||
if (u) {
|
||||
await navigateTo('/platform')
|
||||
} else {
|
||||
error.value = '登录失败'
|
||||
}
|
||||
loading.value = false
|
||||
async function doSubmit() {
|
||||
error.value = ''; msg.value = ''; loading.value = true
|
||||
if (!phone.value || !password.value) { error.value = '请填写手机号和密码'; loading.value = false; return }
|
||||
if (mode.value === 'register' && !name.value) { error.value = '请填写姓名'; loading.value = false; return }
|
||||
|
||||
const endpoint = mode.value === 'login' ? '/api/hss/auth/login' : '/api/hss/auth/register'
|
||||
const body: any = { phone: phone.value, password: password.value }
|
||||
if (mode.value === 'register') { body.name = name.value; body.role = 'STAFF' }
|
||||
|
||||
try {
|
||||
const res = await $fetch<any>(endpoint, { method:'POST', body: JSON.stringify(body), headers:{'Content-Type':'application/json'} })
|
||||
if (res.code === 200 && res.data?.token) {
|
||||
setAuth({ token: res.data.token, userId: res.data.userId, name: res.data.name, role: res.data.role })
|
||||
msg.value = mode.value === 'register' ? '注册成功,正在跳转...' : '登录成功,正在跳转...'
|
||||
setTimeout(() => navigateTo('/platform'), 800)
|
||||
} else {
|
||||
error.value = res.message || '操作失败'
|
||||
}
|
||||
} catch(e: any) { error.value = e?.data?.message || e?.message || '网络错误' }
|
||||
finally { loading.value = false }
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -28,31 +42,37 @@ async function doLogin() {
|
||||
<span class="text-white font-bold text-2xl font-mono">H</span>
|
||||
</div>
|
||||
<h1 class="text-2xl font-bold">智慧医养居家上门服务平台</h1>
|
||||
<p class="text-text-secondary text-sm mt-2">演示环境 — 选择角色即可登录</p>
|
||||
<p class="text-text-secondary text-sm mt-2">{{ mode === 'login' ? '登录您的账号' : '注册新账号' }}</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-2xl shadow-sm border p-6 space-y-4">
|
||||
<label class="block text-sm font-medium text-text-secondary">选择登录角色</label>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<button v-for="(u, k) in PRESET_USERS" :key="k"
|
||||
@click="selected = k"
|
||||
class="text-left px-4 py-3 rounded-xl border-2 transition-all text-sm"
|
||||
:class="selected === k ? 'border-primary bg-primary-50 text-primary' : 'border-gray-100 hover:border-gray-200'">
|
||||
<div class="font-medium">{{ u.userName }}</div>
|
||||
<div class="text-xs text-text-secondary">{{ u.userRole }}</div>
|
||||
</button>
|
||||
<div class="flex border-b mb-2">
|
||||
<button @click="mode='login';error='';msg=''" :class="['flex-1 py-2 text-sm font-medium border-b-2 transition-colors', mode==='login'?'border-primary text-primary':'border-transparent text-text-secondary']">登录</button>
|
||||
<button @click="mode='register';error='';msg=''" :class="['flex-1 py-2 text-sm font-medium border-b-2 transition-colors', mode==='register'?'border-primary text-primary':'border-transparent text-text-secondary']">注册</button>
|
||||
</div>
|
||||
|
||||
<div v-if="mode==='register'">
|
||||
<label class="block text-xs text-text-secondary mb-1">姓名</label>
|
||||
<input v-model="name" class="w-full px-4 py-3 border rounded-xl text-sm outline-none focus:border-primary" placeholder="您的姓名"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs text-text-secondary mb-1">手机号</label>
|
||||
<input v-model="phone" type="tel" class="w-full px-4 py-3 border rounded-xl text-sm outline-none focus:border-primary" placeholder="11位手机号"/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs text-text-secondary mb-1">密码</label>
|
||||
<input v-model="password" type="password" class="w-full px-4 py-3 border rounded-xl text-sm outline-none focus:border-primary" placeholder="输入密码"/>
|
||||
</div>
|
||||
|
||||
<p v-if="error" class="text-red-500 text-sm text-center">{{ error }}</p>
|
||||
<p v-if="msg" class="text-green-500 text-sm text-center">{{ msg }}</p>
|
||||
|
||||
<button @click="doLogin" :disabled="loading"
|
||||
<button @click="doSubmit" :disabled="loading"
|
||||
class="w-full py-3 bg-primary text-white rounded-xl font-semibold hover:bg-primary-700 transition-colors disabled:opacity-50">
|
||||
{{ loading ? '登录中...' : '进入平台' }}
|
||||
{{ loading ? '请稍候...' : mode === 'login' ? '登录' : '注册' }}
|
||||
</button>
|
||||
|
||||
<p class="text-xs text-text-secondary text-center">
|
||||
演示环境使用 Header 认证,无需密码。选择角色后直接进入对应工作台。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user